home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Macros1.p < prev    next >
Encoding:
Text File  |  1997-05-05  |  132.0 KB  |  6,020 lines  |  [TEXT/CWIE]

  1. unit Macros1;
  2. {Contains the recursive descent parser/interpreter}
  3. {for NIH Image's Pascal-like macro language.}
  4.  
  5. {References:}
  6. {  "Pascal User Manual and Report", Kathleen Jensen and Niklaus Wirth, Springer-Verlag}
  7. {  "Building Your Own C Interpreter", Dr. Dobb's Journal, August 1989}
  8.  
  9. interface
  10.  
  11.     uses
  12.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  13.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows, OSUtils,
  14.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  15.         Folders, ColorPicker,
  16.         Globals, Utilities, RealUtils, Graphics, Edit, Dialogs, Files, Windows,
  17.         Analysis, Camera, File1, File2, Filters, Macros2, Stacks, Lut, Background,
  18.         User, Devices, Serial, PlugIns, Text, projection, math, fft, Edm;
  19.  
  20.  
  21.     procedure RunMacro (nMacro: integer);
  22.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  23.     procedure CloseSerialPorts;
  24.  
  25.  
  26. implementation
  27.  
  28.     const
  29.         EndExpected = '"end" or ";" expected';
  30.         ThenExpected = '"then" expected';
  31.         DivideByZero = 'Divide by zero';
  32.         DoExpected = '"do" expected';
  33.         UntilExpected = '"until" expected';
  34.         RightParenExpected = '")" expected';
  35.         NoImageOpen = 'No Image open';
  36.         MaxArgs = 25;
  37.         MaxLoopCount = 20;
  38.         
  39.     var
  40.         nSaves, ErrorPC, LineStartPC: integer;
  41.         SaveBackground: integer;
  42.         SavePicWidth, SavePicHeight: LongInt;
  43.         SaveMethod: rsMethodType;
  44.         SaveCreate, SaveInvertY, SaveScaleArithmetic, SaveScaleConvolutions: boolean;
  45.         SaveCurrentFontID, SaveCurrentSize, SaveTextJust: integer;
  46.         SaveCurrentStyle: Style;
  47.         SaveTextBack: TextBackType;
  48.         SaveAngle, SaveH, SaveV: extended;
  49.         DoOption, MacroOpPending, StringsAllocated, InPhotoMode: boolean;
  50.         RoutinesCalled: set of CommandType;
  51.         MacroTicks: LongInt;
  52.         LoopCounter: LongInt;
  53.     
  54.  
  55.  
  56.     procedure test;
  57.     var
  58.       op:TokenTypeX;
  59.     begin
  60.         op:=token;
  61.     end;
  62.  
  63.  
  64.     function GetExpression: extended;
  65.     forward;
  66.     function GetBooleanExpression: extended;
  67.     forward;
  68.     procedure DoStatement;
  69.     forward;
  70.     procedure SkipStatement;
  71.     forward;
  72.     procedure DoFor;
  73.     forward;
  74.     procedure MacroError (str: str255);
  75.     forward;
  76.     function GetString: str255;
  77.     forward;
  78.     function GetInteger: LongInt;
  79.     forward;
  80.     procedure SkipIf;
  81.     forward;
  82.     procedure SkipPartialStatement;
  83.     forward;
  84.     procedure DoUserFunction;
  85.     forward;
  86.  
  87.  
  88. {$S MacroUtil}
  89. {Routines from here to the $S compiler directive go in the MacroUtil segment}
  90.  
  91.  
  92.     
  93.     
  94.     procedure PutTokenBack;
  95.     begin
  96.         if token <> DoneT then begin
  97.                 pc := SavePC;
  98.                 token := SaveToken;
  99.             end;
  100.     end;
  101.  
  102.  
  103.     procedure DeallocateStrings (first, last: integer);
  104.         var
  105.             i: integer;
  106.     begin
  107.         with MacrosP^ do begin
  108.                 for i := first to last do begin
  109.                         if Stack[i].StringH <> nil then begin
  110.                                 DisposeHandle(handle(Stack[i].StringH));
  111.                                 Stack[i].StringH := nil;
  112.                             end;
  113.                     end;
  114.             end;
  115.     end;
  116.  
  117.  
  118.     procedure TrimString (var str: str255);
  119.     begin
  120.         if length(str) > 0 then begin
  121.                 while (length(str) > 1) and (str[1] = ' ') do
  122.                     delete(str, 1, 1);
  123.                 while (length(str) > 1) and ((str[length(str)] = ' ') or (str[length(str)] = ';')) do
  124.                     delete(str, length(str), 1);
  125.             end;
  126.     end;
  127.  
  128.  
  129.     procedure LookupVariable;
  130.         var
  131.             VarFound: boolean;
  132.             i: integer;
  133.     begin
  134.         with MacrosP^ do begin
  135.                 VarFound := false;
  136.                 i := TopOfStack + 1;
  137.                 repeat
  138.                     i := i - 1;
  139.                     VarFound := SymbolTableLoc = Stack[i].SymbolTableIndex
  140.                 until VarFound or (i = 1);
  141.                 if VarFound then
  142.                     with stack[i] do begin
  143.                             TokenValue := value;
  144.                             if vType <> StringVar then
  145.                                 token := Variable
  146.                             else begin
  147.                                     token := StringVariable;
  148.                                     if StringH <> nil then
  149.                                         TokenStr := StringH^^
  150.                                     else
  151.                                         TokenStr := 'Deallocated String';
  152.                                 end;
  153.                             TokenStackLoc := i;
  154.                         end;
  155.             end; {with}
  156.     end;
  157.  
  158.  
  159.     function FetchInteger: integer;
  160.         var
  161.             temp: integer;
  162.     begin
  163.         with macrosP^ do begin
  164.                 temp := ord(macros[pc]);
  165.                 pc := pc + 1;
  166.                 FetchInteger := bor(bsl(temp, 8),  ord(macros[pc]));
  167.                 pc := pc + 1;
  168.             end;
  169.     end;
  170.  
  171.  
  172.     procedure LookupProcedureOrFunction;
  173.     begin
  174.         with MacrosP^ do begin
  175.                 SymbolTableLoc := FetchInteger;
  176.                 with SymbolTable[SymbolTableLoc] do begin
  177.                         TokenLoc := loc;
  178.                         TokenSymbol := symbol;
  179.                     end;
  180.             end;
  181.     end;
  182.  
  183.  
  184. function FetchReal: real;
  185.         type
  186.             bytes=packed array[1..4] of char;
  187.         var
  188.             vrec:record
  189.                 case integer of
  190.                     1: (rv: real);
  191.                     2: (b: bytes)
  192.                 end;
  193.     begin
  194.         with macrosP^,vrec do begin
  195.             b[1] := macros[pc];
  196.             pc := pc + 1;
  197.             b[2] := macros[pc];
  198.             pc := pc + 1;
  199.             b[3] := macros[pc];
  200.             pc := pc + 1;
  201.             b[4] := macros[pc];
  202.             pc := pc + 1;
  203.             FetchReal:=rv;
  204.         end;
  205.     end;
  206.  
  207.  
  208.     procedure GetToken;
  209.     begin
  210.         with MacrosP^ do begin
  211.                 if token = DoneT then
  212.                     exit(GetToken);
  213.                 SavePC := PC;
  214.                 SaveToken := token;
  215.                 token := TokenTypeX(ord(macros[pc]));
  216.                 while token = NewLineT do begin
  217.                         MacroLineNumber := MacroLineNumber + 1;
  218.                         pc := pc + 1;
  219.                         LineStartPC := pc;
  220.                         if pc > EndMacros then begin
  221.                                 Token := DoneT;
  222.                                 exit(GetToken);
  223.                             end;
  224.                         SavePC := PC;
  225.                         SaveToken := token;
  226.                         token := TokenTypeX(band(ord(macros[pc]),255));
  227.                     end;
  228.                 pc := pc + 1;
  229.                 if pc > EndMacros then begin
  230.                         Token := DoneT;
  231.                         exit(GetToken);
  232.                     end;
  233.                 case token of
  234.                     CommandT, FunctionT, StringFunctionT, ArrayT:
  235.                         begin
  236.                             MacroCommand := CommandType(ord(macros[pc]));
  237.                             pc := pc + 1;
  238.                         end;
  239.                     Identifier:  begin
  240.                             SymbolTableLoc := FetchInteger;
  241.                             if TopOfStack > 0 then
  242.                                 LookupVariable;
  243.                         end;
  244.                     ProcedureT, UserFunctionT: 
  245.                         LookupProcedureOrFunction;
  246.                     NumericLiteral: 
  247.                         TokenValue := FetchReal;
  248.                     StringLiteral:  begin
  249.                             TokenStr := '';
  250.                             while ord(macros[pc]) <> 0 do begin
  251.                                     TokenStr := Concat(TokenStr, macros[pc]);
  252.                                     pc := pc + 1;
  253.                                 end;
  254.                             pc := pc + 1;
  255.                         end;
  256.                 end; {case}
  257.             end; {with}
  258.     end;
  259.  
  260.  
  261.     procedure GetMacroName;
  262.         var
  263.             i, len: integer;
  264.     begin
  265.         with MacrosP^ do begin
  266.                 pc := PCStart;
  267.                 repeat
  268.                     pc := pc - 1;
  269.                     if pc < 0 then
  270.                         exit(GetMacroName);
  271.                 until macros[pc] = chr(ord(MacroT));
  272.                 GetToken; {MacroT}
  273.                 GetToken; {Macro name}
  274.                 if Token = StringLiteral then begin
  275.                         len := length(TokenStr);
  276.                         if len > SymbolSize then
  277.                             len := SymbolSize;
  278.                         for i := 1 to len do
  279.                             MacroOrProcName[i] := TokenStr[i];
  280.                     end;
  281.             end;
  282.     end;
  283.  
  284.  
  285.     procedure ConvertTokenToString (var str: str255);
  286.         var
  287.             i, j, len: integer;
  288.     begin
  289.         with MacrosP^ do
  290.             case token of
  291.                 semicolon: 
  292.                     str := ';';
  293.                 comma: 
  294.                     str := ',';
  295.                 colon: 
  296.                     str := ':';
  297.                 LeftParen: 
  298.                     str := '(';
  299.                 RightParen: 
  300.                     str := ')';
  301.                 LeftBracket: 
  302.                     str := '[';
  303.                 RightBracket: 
  304.                     str := ']';
  305.                 PlusOp: 
  306.                     str := '+';
  307.                 MinusOp: 
  308.                     str := '-';
  309.                 MulOp: 
  310.                     str := '*';
  311.                 DivOp: 
  312.                     str := '/';
  313.                 eqOp: 
  314.                     str := '=';
  315.                 ltOp: 
  316.                     str := '<';
  317.                 gtOp: 
  318.                     str := '>';
  319.                 neOp: 
  320.                     str := '<>';
  321.                 leOp: 
  322.                     str := '<=';
  323.                 geOp: 
  324.                     str := '>=';
  325.                 orOp: 
  326.                     str := 'or';
  327.                 IntDivOp: 
  328.                     str := 'div';
  329.                 modOp: 
  330.                     str := 'mod';
  331.                 andOp: 
  332.                     str := 'and';
  333.                 NotOp: 
  334.                     str := 'not';
  335.                 AssignOp: 
  336.                     str := ':=';
  337.                 Identifier, Variable, StringVariable, ProcIdT, UserFuncIdT:  begin
  338.                         for i := 1 to SymbolSize do
  339.                             str := Concat(str, SymbolTable[SymbolTableLoc].symbol[i]);
  340.                         TrimString(str);
  341.                     end;
  342.                 NumericLiteral:  begin
  343.                         if trunc(TokenValue) = TokenValue then
  344.                             RealToString(TokenValue, 1, 0, str)
  345.                         else
  346.                             RealToString(TokenValue, 1, 1, str);
  347.                     end;
  348.                 StringLiteral: 
  349.                     str := concat('''', TokenStr, '''');
  350.                 CommandT, FunctionT, StringFunctionT, ArrayT, UserFunctionT: 
  351.                     for i := 1 to nSymbols do begin
  352.                             with SymbolTable[i] do
  353.                                 if (tType = token) and (MacroCommand = cType) then begin
  354.                                         for j := 1 to SymbolSize do
  355.                                             str := Concat(str, symbol[j]);
  356.                                         TrimString(str);
  357.                                     end;
  358.                         end; {for}
  359.                 otherwise
  360.                     for i := 1 to nSymbols do begin
  361.                             with SymbolTable[i] do
  362.                                 if tType = token then begin
  363.                                         for j := 1 to SymbolSize do
  364.                                             str := Concat(str, symbol[j]);
  365.                                         TrimString(str);
  366.                                     end;
  367.                         end; {for}
  368.             end; {case}
  369.     end;
  370.  
  371.  
  372.     procedure GetErrorLine (var ErrorLine: str255);
  373.         var
  374.             str: str255;
  375.     begin
  376.         with MacrosP^ do begin
  377.                 pc := LineStartPC;
  378.                 ErrorLine := '';
  379.                 repeat
  380.                     str := '';
  381.                     if ord(macros[pc]) = ord(NewLineT) then {ppc-bug}
  382.                         leave;
  383.                     GetToken;
  384.                     ConvertTokenToString(str);
  385.                     if SavePC = ErrorPC then
  386.                         str := concat('«', str, '»');
  387.                     ErrorLine := concat(ErrorLine, ' ', str);
  388.                 until token = DoneT;
  389.             end;
  390.     end;
  391.  
  392.  
  393.     procedure GetLocalLineNumber;
  394.     begin
  395.         pc := PCStart;
  396.         MacroLineNumber := 1;
  397.         while (pc <= errorpc) and (token <> DoneT) do
  398.             GetToken;
  399.     end;
  400.  
  401.  
  402.     procedure GetGlobalLineNumber;
  403.     begin
  404.         pc := 0;
  405.         MacroLineNumber := 1;
  406.         while (pc <= errorpc) and (token <> DoneT) do
  407.             GetToken;
  408.     end;
  409.     
  410.  
  411.     procedure MacroError (str: str255);
  412.   {Report run-time errors}
  413.         var
  414.             name, ErrorLine, Line: str255;
  415.             i, count, ignore: integer;
  416.     begin
  417.         with MacrosP^ do begin
  418.                 if token = DoneT then
  419.                     exit(MacroError);
  420.                 if TopOfStack > 0 then
  421.                     DeAllocateStrings(nGlobals + 1, TopOfStack);
  422.                 ErrorPC := SavePC;
  423.                 if MacroOrProcName = BlankSymbol then
  424.                     GetMacroName;
  425.                 if MacroOrProcName[SymbolSize] <> ' ' then
  426.                     MacroOrProcName[SymbolSize] := '…';
  427.                 name:='123456789012';
  428.                 for i:=1 to 12 do name[i]:=MacroOrProcName[i];
  429.                 TrimString(name);
  430.                 GetLocalLineNumber;
  431.                 Line := StringOf(MacroLineNumber:1);
  432.                 GetErrorLine(ErrorLine);
  433.                 InitCursor;
  434.                 GetGlobalLineNumber;
  435.                 Line:=StringOf(Line,' (',MacroLineNumber:1,')');
  436.                 ParamText(str, Line, Name, ErrorLine);
  437.                 Ignore := Alert(900, nil);
  438.                 Token := DoneT;
  439.             end; {with}
  440.     end;
  441.  
  442.  
  443.     procedure DoDeclaration;
  444.         var
  445.             SaveStackLoc, StackLoc: integer;
  446.     begin
  447.         SaveStackLoc := TopOfStack;
  448.         while (token = Identifier) or (token = variable) or (token = comma) or (token = StringVariable) do begin
  449.                 if TopOfStack >= MaxMacroStackSize then begin
  450.                         MacroError(StackOverflow);
  451.                         exit(DoDeclaration);
  452.                     end;
  453.                 TopOfStack := TopOfStack + 1;
  454.                 with MacrosP^.stack[TopOfStack] do begin
  455.                         SymbolTableIndex := SymbolTableLoc;
  456.                         value := 0.0;
  457.                         StringH := nil;
  458.                     end;
  459.                 GetToken;
  460.                 if token = comma then
  461.                     GetToken;
  462.             end; {while}
  463.         if (token = FunctionT) or (token = StringFunctionT) or (token = CommandT) or (token = ArrayT) then
  464.             MacroError('Predefined identifier');
  465.         if token <> colon then
  466.             MacroError('":" expected');
  467.         GetToken;
  468.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) and (token <> StringT) then
  469.             MacroError('"integer", "real", "boolean" or "string" expected');
  470.         for StackLoc := SaveStackLoc + 1 to TopOfStack do
  471.             with macrosP^.stack[StackLoc] do
  472.                 case token of
  473.                     IntegerT: 
  474.                         vType := IntVar;
  475.                     RealT: 
  476.                         vType := RealVar;
  477.                     BooleanT: 
  478.                         vType := BooleanVar;
  479.                     StringT:  begin
  480.                             StringsAllocated := true;
  481.                             vType := StringVar;
  482.                             StringH := str255H(NewHandle(SizeOf(str255)));
  483.                             if StringH = nil then begin
  484.                                     MacroError('Out of memory');
  485.                                     Token := DoneT
  486.                                 end
  487.                             else
  488.                                 StringH^^ := 'Local String';
  489.                         end;
  490.                     otherwise
  491.                 end;
  492.         GetToken;
  493.         if Token = SemiColon then
  494.             GetToken;
  495.     end;
  496.  
  497.  
  498.     procedure GetLeftParen;
  499.     begin
  500.         GetToken;
  501.         if token <> LeftParen then
  502.             MacroError('"(" expected');
  503.     end;
  504.  
  505.  
  506.     procedure GetRightParen;
  507.     begin
  508.         GetToken;
  509.         if token <> RightParen then
  510.             MacroError(RightParenExpected);
  511.     end;
  512.  
  513.  
  514.     procedure GetComma;
  515.     begin
  516.         GetToken;
  517.         if token <> comma then
  518.             MacroError('"," expected');
  519.     end;
  520.  
  521.  
  522.     procedure GetArguments (var str: str255);
  523.         var
  524.             width, fwidth: integer;
  525.             i: LongInt;
  526.             isExpression, ZeroFill, noArgs, notFormatted: boolean;
  527.             isUserFunction: boolean;
  528.             n: extended;
  529.             str2: str255;
  530.     begin
  531.         if MacroCommand = WritelnC then begin {Check for Writeln with no arguments}
  532.                 GetToken;
  533.                 noArgs := token <> LeftParen;
  534.                 PutTokenBack;
  535.                 if NoArgs then begin
  536.                         str := '';
  537.                         exit(GetArguments);
  538.                     end;
  539.             end;
  540.         ZeroFill := not (MacroCommand in [DrawTextC, WriteC, WritelnC, PutMsgC, ShowMsgC, PutSerialC, ConcatC]);
  541.         width := 4;
  542.         fwidth := 0;
  543.         str := '';
  544.         GetLeftParen;
  545.         GetToken;
  546.         repeat
  547.             notFormatted := true;
  548.             if token = UserFunctionT then begin
  549.                     DoUserFunction;
  550.                     isExpression := TokenStr = 'No return string';
  551.                     if isExpression then
  552.                         n := TokenValue
  553.                     else
  554.                         str2 := TokenStr;
  555.             end else begin
  556.                     isExpression := token in [Variable, NumericLiteral, FunctionT, TrueT, FalseT, ArrayT, MinusOp, LeftParen];
  557.                     PutTokenBack;
  558.                     if isExpression then
  559.                         n := GetBooleanExpression
  560.                     else
  561.                         str2 := GetString;
  562.             end;
  563.             GetToken;
  564.             if token = colon then begin
  565.                     notFormatted := false;
  566.                     width := GetInteger;
  567.                     if width < 0 then
  568.                         width := 0;
  569.                     if width > 100 then
  570.                         width := 100;
  571.                     GetToken;
  572.                     if token = colon then begin
  573.                             fwidth := GetInteger;
  574.                             if fwidth < 0 then
  575.                                 width := 0;
  576.                             if fwidth > 12 then
  577.                                 width := 12;
  578.                             GetToken;
  579.                         end;
  580.                 end;
  581.             if token = comma then
  582.                 GetToken;
  583.             if isExpression then begin
  584.                     if notFormatted then
  585.                         if (trunc(n) <> n) and (not ZeroFill) then begin
  586.                                 width := 1;
  587.                                 fwidth := 4;
  588.                             end;
  589.                     str2:=StringOf(n:width:fwidth);
  590.                     if ZeroFill and (n >= 0) then
  591.                         for i := 1 to width do
  592.                             if str2[i] = ' ' then
  593.                                 str2[i] := '0';
  594.                 end;
  595.             str := concat(str, str2);
  596.         until (token = RightParen) or (token = DoneT);
  597.     end;
  598.  
  599.  
  600.     function DoGetString: str255; {(prompt,default:str255)}
  601.         const
  602.             StringID = 3;
  603.         var
  604.             prompt, default: str255;
  605.             Canceled: boolean;
  606.             mylog: DialogPtr;
  607.             item: integer;
  608.     begin
  609.         GetLeftParen;
  610.         prompt := GetString;
  611.         GetToken;
  612.         if token = Comma then
  613.             default := GetString
  614.         else begin
  615.                 default := '';
  616.                 PutTokenBack
  617.             end;
  618.         GetRightParen;
  619.         if Token <> DoneT then begin
  620.                 InitCursor;
  621.                 ParamText(prompt, '', '', '');
  622.                 mylog := GetNewDialog(170, nil, pointer(-1));
  623.                 SetDString(MyLog, StringID, default);
  624.                 SelectdialogItemText(MyLog, StringID, 0, 32767);
  625.                 OutlineButton(MyLog, ok, 16);
  626.                 repeat
  627.                     ModalDialog(nil, item);
  628.                 until (item = ok) or (item = cancel);
  629.                 if item = ok then
  630.                     DoGetString := GetDString(MyLog, StringID)
  631.                 else begin
  632.                         DoGetString := 'cancel';
  633.                         token := DoneT;
  634.                     end;
  635.                 DisposeDialog(mylog);
  636.             end;
  637.     end;
  638.  
  639.  
  640.     function GetSerial: str255;
  641.         var
  642.             count: LongInt;
  643.             buffer: packed array[1..100] of char;
  644.             err: OSErr;
  645.             c:char;
  646.     begin
  647.         if SerialBufferP = nil then begin
  648.                 MacroError('Serial port not open');
  649.                 exit(GetSerial);
  650.             end;
  651.         Err := SerGetBuf(SerialIn, count);
  652.         if count > 0 then begin
  653.                 count := 1;
  654.             Err := FSRead(SerialIn, count, @buffer);
  655.             c:=buffer[1]; {ppc-bug}
  656.             GetSerial :=c;
  657.             end
  658.         else
  659.             GetSerial := '';
  660.     end;
  661.  
  662.  
  663.     procedure RangeCheck (i: LongInt);
  664.     begin
  665.         if (i < 0) or (i > 255) then
  666.             MacroError('Argument is less than 0 or greater than 255');
  667.     end;
  668.  
  669.  
  670.     function DoChr: str255;
  671.         var
  672.             i: LongInt;
  673.     begin
  674.         GetLeftParen;
  675.         i := GetInteger;
  676.         GetRightParen;
  677.         RangeCheck(i);
  678.         if Token <> DoneT then begin
  679.             DoChr := chr(i);
  680.         end;
  681.     end;
  682.  
  683.  
  684.     function GetWindowTitle: str255;
  685.         var
  686.             wPeek: WindowPeek;
  687.     begin
  688.         wPeek := WindowPeek(FrontWindow);
  689.         if wPeek = nil then begin
  690.                 GetWindowTitle := '';
  691.                 exit(GetWindowTitle);
  692.             end;
  693.         if wPeek^.WindowKind = PicKind then
  694.             GetWindowTitle := Info^.title
  695.         else
  696.             GetWindowTitle := wPeek^.TitleHandle^^;
  697.     end;
  698.  
  699.  
  700.     function GetPath (vRefnum: Integer; DirID: LongInt): Str255;
  701.     { from 'Inside Macintosh: Files' }
  702.     var
  703.       myPB:     CInfoPBRec;
  704.       dirName:  Str255;
  705.       fullPath: Str255;
  706.       myErr:    OSErr;
  707.     begin
  708.       fullPath := '';
  709.       myPB.ioNamePtr := @dirName;
  710.       myPB.ioVRefNum := vRefNum;
  711.       myPB.ioDrParID := DirId;
  712.       myPB.ioFDirIndex := -1;
  713.       repeat
  714.         myPB.ioDrDirID := myPB.ioDrParID;
  715.         myErr := PBGetCatInfoSync(@myPB);
  716.         dirName := concat(dirName, ':');
  717.         fullPath := concat(dirName, fullPath);
  718.       until myPB.ioDrDirID = fsRtDirID;
  719.       GetPath := fullPath;
  720.     end;
  721.  
  722.  
  723.     function DoGetPath: str255;
  724.     var
  725.         err: OSErr;
  726.         PrefsVRef: integer;
  727.         PrefsDirID: LongInt;
  728.         PathType: str255;
  729.     begin
  730.         GetLeftParen;
  731.         PathType := GetString;
  732.         GetRightParen;
  733.         if Token <> DoneT then begin
  734.             DoGetPath := '';
  735.             MakeLowerCase(PathType);
  736.             if pos('window', PathType) <> 0 then begin
  737.                 if (CurrentWindow = textKind) and (TextInfo <> nil) then begin
  738.                     if TextInfo^.TextRefNum <> 0 then
  739.                         DoGetPath := GetPath(TextInfo^.TextRefNum, 0)
  740.                 end else if (CurrentWindow = PicKind) and (info^.vRef <> 0) then
  741.                     DoGetPath := GetPath(info^.vRef, 0)
  742.             end else if pos('start', PathType) <> 0 then
  743.                 DoGetPath := GetPath(StartupSpec.vRefNum, StartupSpec.parID)
  744.             else if pos('pref', PathType) <> 0 then begin
  745.                 err:=FindFolder(kOnSystemDisk, kPreferencesFolderType,
  746.                     kDontCreateFolder, PrefsVRef, PrefsDirID);
  747.                 if err = noErr then
  748.                     DoGetPath := GetPath(PrefsVRef, PrefsDirID)
  749.             end else
  750.                 MacroError('Unrecognized argument');
  751.         end;
  752.     end;
  753.     
  754.     
  755.     function DoStringFunction: str255;
  756.         var
  757.             str: str255;
  758.     begin
  759.         case MacroCommand of
  760.             GetStringC: 
  761.                 DoStringFunction := DoGetString;
  762.             ChrC: 
  763.                 DoStringFunction := DoChr;
  764.             GetSerialC: 
  765.                 DoStringFunction := GetSerial;
  766.             ConcatC:  begin
  767.                     GetArguments(str);
  768.                     DoStringFunction := str;
  769.                 end;
  770.             WindowTitleC: 
  771.                 DoStringFunction := GetWindowTitle;
  772.             GetPathC:
  773.                 DoStringFunction := DoGetPath;
  774.             otherwise
  775.                 MacroError('"GetString ", "GetSerial" or "chr" expected');
  776.         end;
  777.     end;
  778.  
  779.  
  780.     function GetString: str255;
  781.     begin
  782.         GetToken;
  783.         if token = StringFunctionT then
  784.             GetString := DoStringFunction
  785.         else if (token = StringLiteral) or (token = StringVariable) then
  786.             GetString := TokenStr
  787.         else if token = UserFunctionT then begin
  788.             DoUserFunction;
  789.             GetString := TokenStr
  790.         end else begin
  791.                 MacroError('String expected');
  792.                 GetString := '';
  793.             end;
  794.     end;
  795.  
  796.  
  797.     function GetInteger: LongInt;
  798.         var
  799.             n: LongInt;
  800.             r: extended;
  801.     begin
  802.         r := GetExpression;
  803.         if token = DoneT then begin
  804.                 GetInteger := 0;
  805.                 exit(GetInteger);
  806.             end;
  807.         GetInteger := round(r);
  808.     end;
  809.  
  810.  
  811.     procedure CheckBoolean (b: extended);
  812.     begin
  813.         if (b <> ord(true)) and (b <> ord(false)) then
  814.             MacroError('Boolean expression expected');
  815.     end;
  816.  
  817.  
  818.     function GetBoolean: boolean;
  819.         var
  820.             value: extended;
  821.     begin
  822.         value := GetBooleanExpression;
  823.         CheckBoolean(value);
  824.         GetBoolean := value = ord(true);
  825.     end;
  826.  
  827.  
  828.     function GetBooleanArg: boolean;
  829.     begin
  830.         GetLeftParen;
  831.         GetBooleanArg := GetBoolean;
  832.         GetRightParen;
  833.     end;
  834.  
  835.  
  836.     function GetStringArg: str255;
  837.     begin
  838.         GetLeftParen;
  839.         GetStringArg := GetString;
  840.         GetRightParen;
  841.     end;
  842.  
  843.  
  844.     procedure DoConvolve;
  845.         var
  846.             err: OSErr;
  847.             f: integer;
  848.             FileFound: boolean;
  849.             fname: str255;
  850.     begin
  851.         fname := GetStringArg;
  852.         if token <> DoneT then begin
  853.                 if (fname = '') and (CurrentWindow = TextKind) then begin
  854.                         ConvolveUsingText;
  855.                         exit(DoConvolve);
  856.                     end;
  857.                 err := fsopen(fname, KernelsRefNum, f);
  858.                 FileFound := err = NoErr;
  859.                 err := fsclose(f);
  860.                 if FileFound then
  861.                     convolve(fname, KernelsRefNum)
  862.                 else
  863.                     convolve('', 0);
  864.             end;
  865.     end;
  866.  
  867.  
  868.     function GetNumber: extended; {(prompt:str255; default:extended; [DefaultDigits:integer])}
  869.         var
  870.             prompt: str255;
  871.             default, n: extended;
  872.             Canceled, OptionalArgument: boolean;
  873.             DefaultDigits: LongInt;
  874.     begin
  875.         GetLeftParen;
  876.         prompt := GetString;
  877.         GetComma;
  878.         default := GetExpression;
  879.         GetToken;
  880.         OptionalArgument := token <> RightParen;
  881.         PutTokenBack;
  882.         if OptionalArgument then begin
  883.                 GetComma;
  884.                 DefaultDigits := GetInteger;
  885.                 if DefaultDigits < 0 then
  886.                     DefaultDigits := 0;
  887.                 if DefaultDigits > 5 then
  888.                     DefaultDigits := 5;
  889.         end else
  890.                 DefaultDigits := 2;
  891.         GetRightParen;
  892.         n := 0.0;
  893.         if Token <> DoneT then begin
  894.                 n := GetReal(prompt, default, DefaultDigits, Canceled);
  895.                 if Canceled then begin
  896.                         n := default;
  897.                         token := DoneT;
  898.                     end;
  899.             end;
  900.         GetNumber := n;
  901.     end;
  902.  
  903.  
  904.     function DoGetPixel: extended; {(hloc,vloc:integer)}
  905.         var
  906.             hloc, vloc: LongInt;
  907.     begin
  908.         GetLeftParen;
  909.         hloc := GetInteger;
  910.         GetComma;
  911.         vloc := GetInteger;
  912.         GetRightParen;
  913.         if (Token <> DoneT) and (info <> NoInfo) then
  914.             DoGetPixel := MyGetPixel(hloc, vloc)
  915.         else
  916.             DoGetPixel := 0.0;
  917.     end;
  918.  
  919.  
  920.     function DoFunction (c: CommandType): extended;
  921.         var
  922.             n: extended;
  923.             SaveCommand: CommandType;
  924.     begin
  925.         SaveCommand := MacroCommand;
  926.         GetLeftParen;
  927.         n := GetExpression;
  928.         GetRightParen;
  929.         if Token <> DoneT then
  930.             case SaveCommand of
  931.                 truncC: 
  932.                     DoFunction := trunc(n);
  933.                 roundC: 
  934.                     DoFunction := round(n);
  935.                 oddC: 
  936.                     if odd(trunc(n)) then
  937.                         DoFunction := ord(true)
  938.                     else
  939.                         DoFunction := ord(false);
  940.                 absC: 
  941.                     DoFunction := abs(n);
  942.                 sqrtC: 
  943.                     if n < 0.0 then
  944.                         MacroError('Sqrt Error')
  945.                     else
  946.                         DoFunction := sqrt(n);
  947.                 sqrC: 
  948.                     DoFunction := sqr(n);
  949.                 sinC: 
  950.                     DoFunction := sin(n);
  951.                 cosC: 
  952.                     DoFunction := cos(n);
  953.                 expC: 
  954.                     DoFunction := exp(n);
  955.                 lnC: 
  956.                     if n <= 0.0 then
  957.                         MacroError('Log Error')
  958.                     else
  959.                         DoFunction := ln(n);
  960.                 arctanC: 
  961.                     DoFunction := arctan(n);
  962.             end
  963.         else
  964.             DoFunction := 0.0;
  965.     end;
  966.  
  967.  
  968.     function CalibrateValue: extended;
  969.         var
  970.             i: integer;
  971.     begin
  972.         GetLeftParen;
  973.         i := GetInteger;
  974.         GetRightParen;
  975.         RangeCheck(i);
  976.         if Token <> DoneT then begin
  977.                 CalibrateValue := cvalue[i];
  978.             end;
  979.     end;
  980.  
  981.  
  982.     function DoOrd: extended;
  983.         var
  984.             str: str255;
  985.     begin
  986.         GetLeftParen;
  987.         str := GetString;
  988.         GetRightParen;
  989.         if Token <> DoneT then begin
  990.                 if length(str) >= 1 then
  991.                     DoOrd := ord(str[1])
  992.                 else
  993.                     DoOrd := -1;
  994.             end;
  995.     end;
  996.  
  997.  
  998.     function DoStringToNum: extended;
  999.         var
  1000.             str: str255;
  1001.             n: extended;
  1002.     begin
  1003.         GetLeftParen;
  1004.         str := GetString;
  1005.         GetRightParen;
  1006.         if Token <> DoneT then begin
  1007.                 n := StringToReal(str);
  1008.                 if n = BadReal then
  1009.                     DoStringToNum := 0.0
  1010.                 else
  1011.                     DoStringToNum := n;
  1012.             end;
  1013.     end;
  1014.  
  1015.  
  1016.     function DoLogicalFunction (c: CommandType): extended;
  1017.         var
  1018.             n1, n2: LongInt;
  1019.     begin
  1020.         GetLeftParen;
  1021.         n1 := GetInteger;
  1022.         GetComma;
  1023.         n2 := GetInteger;
  1024.         GetRightParen;
  1025.         if Token <> DoneT then begin
  1026.                 if c = BitAndC then
  1027.                     DoLogicalFunction := band(n1, n2)
  1028.                 else
  1029.                     DoLogicalFunction := bor(n1, n2)
  1030.             end;
  1031.     end;
  1032.  
  1033.  
  1034.     function PidExists: boolean; {(pid:integer)}
  1035.         var
  1036.             pid, i: integer;
  1037.     begin
  1038.         GetLeftParen;
  1039.         pid := GetInteger;
  1040.         GetRightParen;
  1041.         if Token <> DoneT then begin
  1042.                 PidExists := false;
  1043.                 for i := 1 to nPics do
  1044.                     if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = pid then begin
  1045.                             PidExists := true;
  1046.                             leave;
  1047.                         end;
  1048.             end;
  1049.     end;
  1050.  
  1051.  
  1052.     function DoPos: integer;
  1053.         var
  1054.             substr, str: str255;
  1055.     begin
  1056.         GetLeftParen;
  1057.         substr := GetString;
  1058.         GetComma;
  1059.         str := GetString;
  1060.         GetRightParen;
  1061.         if Token <> DoneT then
  1062.             DoPos := pos(substr, str);
  1063.     end;
  1064.  
  1065.  
  1066.     function DoLength: integer;
  1067.         var
  1068.             str: str255;
  1069.     begin
  1070.         GetLeftParen;
  1071.         str := GetString;
  1072.         GetRightParen;
  1073.         if Token <> DoneT then
  1074.             DoLength := length(str);
  1075.     end;
  1076.  
  1077.  
  1078.     function isKeyDown:boolean; {(key:string)}
  1079.         var
  1080.             key: str255;
  1081.     begin
  1082.         GetLeftParen;
  1083.         key := GetString;
  1084.         GetRightParen;
  1085.         if token <> DoneT then begin
  1086.             MakeLowerCase(key);
  1087.             isKeydown:=false;
  1088.             if (pos('option', key) <> 0) and OptionKeyDown then
  1089.                 isKeyDown:=true
  1090.             else if (pos('shift', key) <> 0) and ShiftKeyDown then
  1091.                 isKeyDown:=true
  1092.             else if (pos('control', key) <> 0) and ControlKeyDown then
  1093.                 isKeyDown:=true;
  1094.         end;
  1095.     end;
  1096.  
  1097.  
  1098.     function GetParameter:LongInt; {parameter:string}
  1099.         var
  1100.             param: str255;
  1101.     begin
  1102.         GetLeftParen;
  1103.         param := GetString;
  1104.         GetRightParen;
  1105.         if token <> DoneT then begin
  1106.             MakeLowerCase(param);
  1107.             if pos('maxmeasure', param) <> 0 then
  1108.                 GetParameter := MaxMeasurements
  1109.             else if pos('undo', param) <> 0 then
  1110.                 GetParameter := UndoBufSize
  1111.             else if pos('freemem', param) <> 0 then
  1112.                 GetParameter := FreeMem
  1113.             else if pos('maxblock', param) <> 0 then
  1114.                 GetParameter := MaxBlock
  1115.             else if pos('offset', param) <> 0 then
  1116.                 GetParameter := DacLow
  1117.             else if pos('gain', param) <> 0 then
  1118.                 GetParameter := 255 - (DacHigh - DacLow)
  1119.             else if pos('width', param) <> 0 then
  1120.                 GetParameter := ScreenWidth
  1121.             else if pos('height', param) <> 0 then
  1122.                 GetParameter := ScreenHeight
  1123.             else if pos('roitype', param) <> 0 then begin
  1124.                 if info = nil then
  1125.                     GetParameter := 0
  1126.                 else case Info^.RoiType of
  1127.                     noRoi: GetParameter := 0;
  1128.                     RectRoi: GetParameter := 1;
  1129.                     OvalRoi: GetParameter := 2;
  1130.                     PolygonRoi: GetParameter := 3;
  1131.                     FreehandRoi: GetParameter := 4;
  1132.                     TracedRoi: GetParameter := 5;
  1133.                     LineRoi: GetParameter := 6;
  1134.                     FreeLineRoi: GetParameter := 7;
  1135.                     SegLineRoi: GetParameter := 8;
  1136.                 end
  1137.             end else begin
  1138.                 MacroError('Invalid argument');
  1139.                 GetParameter := 0;
  1140.             end;
  1141.         end;
  1142.     end;
  1143.  
  1144.  
  1145.     function ExecuteFunction: extended;
  1146.     begin
  1147.         case MacroCommand of
  1148.             TruncC, RoundC, oddC, absC, sqrtC, sqrC, sinC, cosC, expC, lnC, arctanC: 
  1149.                 ExecuteFunction := DoFunction(MacroCommand);
  1150.             GetNumC: 
  1151.                 ExecuteFunction := GetNumber;
  1152.             RandomC: 
  1153.                 ExecuteFunction := (random + 32767.0) / 65534.0;
  1154.             GetPixelC: 
  1155.                 ExecuteFunction := DoGetPixel;
  1156.             ButtonC:  begin
  1157.                     ExecuteFunction := ord(Button);
  1158.                     FlushEvents(EveryEvent, 0);
  1159.                 end;
  1160.             nPicsC: 
  1161.                 ExecuteFunction := nPics;
  1162.             PicNumC: 
  1163.                 ExecuteFunction := info^.PicNum;
  1164.             PidNumC: 
  1165.                 ExecuteFunction := info^.PidNum;
  1166.             PidExistsC: 
  1167.                 ExecuteFunction := ord(PidExists);
  1168.             SameSizeC: 
  1169.                 ExecuteFunction := ord(AllSameSize);
  1170.             cValueC: 
  1171.                 ExecuteFunction := CalibrateValue;
  1172.             CalibratedC: 
  1173.                 ExecuteFunction := ord(info^.fit <> uncalibrated);
  1174.             rCountC: 
  1175.                 ExecuteFunction := mCount;
  1176.             GetSliceC: 
  1177.                 with info^ do
  1178.                     if StackInfo = nil then
  1179.                         ExecuteFunction := 0
  1180.                     else
  1181.                         ExecuteFunction := Info^.StackInfo^.CurrentSlice;
  1182.             nSlicesC: 
  1183.                 with info^ do
  1184.                     if StackInfo = nil then
  1185.                         ExecuteFunction := 0
  1186.                     else
  1187.                         ExecuteFunction := Info^.StackInfo^.nSlices;
  1188.             GetSpacingC: 
  1189.                 with info^ do
  1190.                     if StackInfo = nil then
  1191.                         MacroError('No stack')
  1192.                     else with Info^.StackInfo^ do begin
  1193.                         if StackType = MovieStack then
  1194.                             ExecuteFunction := Info^.StackInfo^.FrameInterval
  1195.                         else
  1196.                             ExecuteFunction := Info^.StackInfo^.SliceSpacing;
  1197.                     end;
  1198.             nCoordinatesC: 
  1199.                 ExecuteFunction := nCoordinates;
  1200.             OrdC: 
  1201.                 ExecuteFunction := DoOrd;
  1202.             TickCountC: 
  1203.                 ExecuteFunction := TickCount;
  1204.             StringToNumC: 
  1205.                 ExecuteFunction := DoStringToNum;
  1206.             UndoSizeC: 
  1207.                 ExecuteFunction := UndoBufSize;
  1208.             BitAndC, BitOrC: 
  1209.                 ExecuteFunction := DoLogicalFunction(MacroCommand);
  1210.             PosC: 
  1211.                 ExecuteFunction := DoPos;
  1212.             LengthC: 
  1213.                 ExecuteFunction := DoLength;
  1214.             KeyDownC:
  1215.                 ExecuteFunction := ord(isKeyDown);
  1216.             GetC:
  1217.                 ExecuteFunction := GetParameter;
  1218.         end; {case}
  1219.     end;
  1220.  
  1221.  
  1222.     procedure CheckIndex (index, min, max: LongInt);
  1223.     begin
  1224.         if (index < min) or (index > max) then
  1225.             MacroError('Array index out of range');
  1226.     end;
  1227.  
  1228.  
  1229.     function GetArrayValue: extended;
  1230.         var
  1231.             SaveArrayType: ArrayType;
  1232.             Index: LongInt;
  1233.             xcoord, ycoord: integer;
  1234.     begin
  1235.         SaveArrayType := ArrayType(MacroCommand);
  1236.         GetToken;
  1237.         if token <> LeftBracket then
  1238.             MacroError('"[" expected');
  1239.         Index := GetInteger;
  1240.         GetToken;
  1241.         if token <> RightBracket then
  1242.             MacroError('"]" expected');
  1243.         case SaveArrayType of
  1244.             HistogramA:  begin
  1245.                     RangeCheck(Index);
  1246.                     GetArrayValue := histogram[Index];
  1247.                 end;
  1248.             rAreaA:  begin
  1249.                     CheckIndex(Index, 1, MaxMeasurements);
  1250.                     GetArrayValue := mArea^[Index];
  1251.                 end;
  1252.             rMeanA:  begin
  1253.                     CheckIndex(Index, 1, MaxMeasurements);
  1254.                     GetArrayValue := mean^[Index];
  1255.                 end;
  1256.             rStdDevA:  begin
  1257.                     CheckIndex(Index, 1, MaxMeasurements);
  1258.                     GetArrayValue := sd^[Index];
  1259.                 end;
  1260.             rXA:  begin
  1261.                     CheckIndex(Index, 1, MaxMeasurements);
  1262.                     GetArrayValue := xcenter^[Index];
  1263.                 end;
  1264.             rYA:  begin
  1265.                     CheckIndex(Index, 1, MaxMeasurements);
  1266.                     GetArrayValue := ycenter^[Index];
  1267.                 end;
  1268.             rLengthA:  begin
  1269.                     CheckIndex(Index, 1, MaxMeasurements);
  1270.                     GetArrayValue := pLength^[Index];
  1271.                 end;
  1272.             rMinA:  begin
  1273.                     CheckIndex(Index, 1, MaxMeasurements);
  1274.                     GetArrayValue := mMin^[Index];
  1275.                 end;
  1276.             rMaxA:  begin
  1277.                     CheckIndex(Index, 1, MaxMeasurements);
  1278.                     GetArrayValue := mMax^[Index];
  1279.                 end;
  1280.             rMajorA:  begin
  1281.                     CheckIndex(Index, 1, MaxMeasurements);
  1282.                     GetArrayValue := MajorAxis^[Index];
  1283.                 end;
  1284.             rMinorA:  begin
  1285.                     CheckIndex(Index, 1, MaxMeasurements);
  1286.                     GetArrayValue := MinorAxis^[Index];
  1287.                 end;
  1288.             rAngleA:  begin
  1289.                     CheckIndex(Index, 1, MaxMeasurements);
  1290.                     GetArrayValue := orientation^[Index];
  1291.                 end;
  1292.             rUser1A:  begin
  1293.                     CheckIndex(Index, 1, MaxMeasurements);
  1294.                     GetArrayValue := User1^[Index];
  1295.                 end;
  1296.             rUser2A:  begin
  1297.                     CheckIndex(Index, 1, MaxMeasurements);
  1298.                     GetArrayValue := User2^[Index];
  1299.                 end;
  1300.             RedLutA, GreenLutA, BlueLutA: 
  1301.                 if OptionKeyDown then begin
  1302.                         RangeCheck(Index);
  1303.                         if Token <> DoneT then
  1304.                             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb do
  1305.                                 case SaveArrayType of
  1306.                                     RedLutA: 
  1307.                                         GetArrayValue := band(bsr(red, 8), 255);
  1308.                                     GreenLutA: 
  1309.                                         GetArrayValue := band(bsr(green, 8), 255);
  1310.                                     BlueLutA: 
  1311.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1312.                                 end; {case}
  1313.                     end
  1314.                 else begin
  1315.                         RangeCheck(Index);
  1316.                         if Token <> DoneT then
  1317.                             with osGDevice^^.gdPMap^^.pmTable^^.ctTable[index].rgb do
  1318.                                 case SaveArrayType of
  1319.                                     RedLutA: 
  1320.                                         GetArrayValue := band(bsr(red, 8), 255);
  1321.                                     GreenLutA: 
  1322.                                         GetArrayValue := band(bsr(green, 8), 255);
  1323.                                     BlueLutA: 
  1324.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1325.                                 end; {case}
  1326.                     end;
  1327.             BufferA:  begin
  1328.                     CheckIndex(Index, 0, MaxLine - 1);
  1329.                     if Token <> DoneT then
  1330.                         GetArrayValue := MacrosP^.aLine[index];
  1331.                 end;
  1332.             PlotDataA:  begin
  1333.                     CheckIndex(Index, 0, MaxLine - 1);
  1334.                     if Token <> DoneT then
  1335.                         GetArrayValue := PlotData^[index];
  1336.                 end;
  1337.             xCoordinatesA:  begin
  1338.                     CheckIndex(Index, 1, MaxCoordinates);
  1339.                     if Token <> DoneT then
  1340.                         with info^ do begin
  1341.                                 xcoord := xCoordinates^[index];
  1342.                                 if SpatiallyCalibrated then
  1343.                                     GetArrayValue := xcoord / xScale
  1344.                                 else
  1345.                                     GetArrayValue := xcoord
  1346.                             end;
  1347.                 end;
  1348.             yCoordinatesA:  begin
  1349.                     CheckIndex(Index, 1, MaxCoordinates);
  1350.                     if Token <> DoneT then
  1351.                         with info^ do begin
  1352.                                 ycoord := yCoordinates^[index];
  1353.                                 if InvertYCoordinates and (Info <> NoInfo) then
  1354.                                     ycoord := Info^.PicRect.bottom - ycoord - 1;
  1355.                                 if SpatiallyCalibrated then
  1356.                                     GetArrayValue := ycoord / yScale
  1357.                                 else
  1358.                                     GetArrayValue := ycoord
  1359.                             end;
  1360.                 end;
  1361.             ScionA:  begin
  1362.                     if framegrabber <> ScionLG3 then
  1363.                         MacroError('No Scion LG-3');
  1364.                     if Token <> DoneT then
  1365.                         CheckIndex(Index, 1, 4);
  1366.                     if Token <> DoneT then
  1367.                         case index of
  1368.                             1: 
  1369.                                 GetArrayValue := LG3DacA;
  1370.                             2: 
  1371.                                 GetArrayValue := LG3DacB;
  1372.                             3: 
  1373.                                 GetArrayValue := ControlReg^;
  1374.                             4: 
  1375.                                 GetArrayValue := LG3DataOut;
  1376.                         end;
  1377.                 end;
  1378.         end; {case}
  1379.     end;
  1380.  
  1381.  
  1382.     function GetStringValue: extended;
  1383.  {Convert string to a base 102 number so we can do comparisons.}
  1384.         const
  1385.             base = 102;
  1386.         var
  1387.             i, j: integer;
  1388.             v, k: extended;
  1389.     begin
  1390.         MakeLowerCase(TokenStr);
  1391.         k := 1;
  1392.         v := 0.0;
  1393.         for i := 1 to length(TokenStr) do begin
  1394.                 j := ord(TokenStr[i]);
  1395.                 if j > 127 then
  1396.                     j := 127;
  1397.                 if j >= 91 then
  1398.                     j := j - 26;
  1399.                 v := v + j * k;
  1400.                 k := k * base;
  1401.             end;
  1402.         GetStringValue := v;
  1403.     end;
  1404.  
  1405.  
  1406.  
  1407.     function GetValue: extended;
  1408.     begin
  1409.         case token of
  1410.             Variable, NumericLiteral: 
  1411.                 GetValue := TokenValue;
  1412.             FunctionT: 
  1413.                 GetValue := ExecuteFunction;
  1414.             StringFunctionT:  begin
  1415.                     TokenStr := DoStringFunction;
  1416.                     GetValue := GetStringValue;
  1417.                 end;
  1418.             UserFunctionT:  begin
  1419.                     DoUserFunction;
  1420.                     GetValue := TokenValue;
  1421.                 end;
  1422.             TrueT: 
  1423.                 GetValue := ord(true);
  1424.             FalseT: 
  1425.                 GetValue := ord(false);
  1426.             ArrayT: 
  1427.                 GetValue := GetArrayValue;
  1428.             StringVariable, StringLiteral: 
  1429.                 GetValue := GetStringValue;
  1430.             otherwise begin
  1431.                     MacroError('Number expected');
  1432.                     GetValue := 0.0;
  1433.                     exit(GetValue);
  1434.                 end;
  1435.         end; {case}
  1436.     end;
  1437.  
  1438.  
  1439.     function GetFactor: extended;
  1440.         var
  1441.             fValue: extended;
  1442.             isUnaryMinus, isNot: boolean;
  1443.     begin
  1444.         GetToken;
  1445.         isUnaryMinus := token = MinusOp;
  1446.         isNot := token = NotOp;
  1447.         if isUnaryMinus or isNot then
  1448.             GetToken;
  1449.         case token of
  1450.             Variable, NumericLiteral, FunctionT, UserFunctionT, StringFunctionT, 
  1451.             TrueT, FalseT, ArrayT, StringVariable, StringLiteral: 
  1452.                 fValue := GetValue;
  1453.             LeftParen:  begin
  1454.                     fValue := GetBooleanExpression;
  1455.                     GetRightParen;
  1456.                 end;
  1457.             otherwise begin
  1458.                     macroError('Undefined identifier');
  1459.                     fvalue := 0.0
  1460.                 end;
  1461.         end;
  1462.         if isUnaryMinus then
  1463.             fValue := -fValue;
  1464.         if isNot then
  1465.             if fValue = ord(true) then
  1466.                 fValue := ord(false)
  1467.             else
  1468.                 fValue := ord(true);
  1469.         GetFactor := fValue;
  1470.         GetToken;
  1471.     end;
  1472.  
  1473.  
  1474.     function GetTerm: extended;
  1475.         var
  1476.             tValue, fValue: extended;
  1477.             op: TokenTypeX;
  1478.     begin
  1479.         tValue := GetFactor;
  1480.         while token in [MulOp, IntDivOp, ModOp, DivOp, AndOp] do begin
  1481.                 op := token;
  1482.                 fValue := GetFactor;
  1483.                 case op of
  1484.                     MulOp: 
  1485.                         tValue := tValue * fValue;
  1486.                     IntDivOp: 
  1487.                         if fValue <> 0.0 then
  1488.                             tValue := trunc(tValue) div trunc(fValue)
  1489.                         else
  1490.                             MacroError(DivideByZero);
  1491.                     ModOp: 
  1492.                         if fValue <> 0.0 then
  1493.                             tValue := trunc(tValue) mod trunc(fValue)
  1494.                         else
  1495.                             MacroError(DivideByZero);
  1496.                     DivOp: 
  1497.                         if fValue <> 0.0 then
  1498.                             tValue := tValue / fValue
  1499.                         else
  1500.                             MacroError(DivideByZero);
  1501.                     AndOp:  begin
  1502.                             CheckBoolean(tValue);
  1503.                             CheckBoolean(fValue);
  1504.                             tValue := ord((tValue = ord(true)) and (fValue = ord(true)));
  1505.                         end;
  1506.                 end; {case}
  1507.             end; {while}
  1508.         GetTerm := tValue;
  1509.     end;
  1510.  
  1511.  
  1512.     function GetSimpleExpression: extended;
  1513.         var
  1514.             seValue, tValue: extended;
  1515.             op: TokenTypeX;
  1516.     begin
  1517.         seValue := GetTerm;
  1518.         while token in [PlusOp, MinusOp, OrOp] do begin
  1519.                 op := token;
  1520.                 tValue := GetTerm;
  1521.                 case op of
  1522.                     PlusOp: 
  1523.                         seValue := seValue + tValue;
  1524.                     MinusOp: 
  1525.                         seValue := seValue - tValue;
  1526.                     orOp:  begin
  1527.                             CheckBoolean(seValue);
  1528.                             CheckBoolean(tValue);
  1529.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1530.                         end;
  1531.                 end;
  1532.             end;
  1533.         GetSimpleExpression := seValue;
  1534.     end;
  1535.  
  1536.  
  1537.     function GetExpression: extended;
  1538.         var
  1539.             seValue, tValue: extended;
  1540.             op: TokenTypeX;
  1541.     begin
  1542.         seValue := GetTerm;
  1543.         while token in [PlusOp, MinusOp, OrOp] do begin
  1544.                 op := token;
  1545.                 tValue := GetTerm;
  1546.                 case op of
  1547.                     PlusOp: 
  1548.                         seValue := seValue + tValue;
  1549.                     MinusOp: 
  1550.                         seValue := seValue - tValue;
  1551.                     orOp:  begin
  1552.                             CheckBoolean(seValue);
  1553.                             CheckBoolean(tValue);
  1554.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1555.                         end;
  1556.                 end;
  1557.             end;
  1558.         GetExpression := seValue;
  1559.         PutTokenBack;
  1560.     end;
  1561.  
  1562.  
  1563.     function GetBooleanExpression: extended;
  1564.         var
  1565.             eValue, seValue: extended;
  1566.             op: TokenTypeX;
  1567.     begin
  1568.         eValue := GetSimpleExpression;
  1569.         while token in [eqOp, ltOp, gtOp, neOp, leOp, geOp] do begin
  1570.                 op := token;
  1571.                 seValue := GetSimpleExpression;
  1572.                 case op of
  1573.                     eqOp: 
  1574.                         eValue := ord(eValue = seValue);
  1575.                     ltOp: 
  1576.                         eValue := ord(eValue < seValue);
  1577.                     gtOp: 
  1578.                         eValue := ord(eValue > seValue);
  1579.                     neOp: 
  1580.                         eValue := ord(eValue <> seValue);
  1581.                     leOp: 
  1582.                         eValue := ord(eValue <= seValue);
  1583.                     geOp: 
  1584.                         eValue := ord(eValue >= seValue);
  1585.                 end;
  1586.             end;
  1587.         GetBooleanExpression := eValue;
  1588.         PutTokenBack;
  1589.     end;
  1590.  
  1591.  
  1592. {$S}
  1593. {Routines from here to the end of the file go in the macro1 segment}
  1594.  
  1595.     procedure DoCapture;
  1596.     begin
  1597.         CaptureAndDisplayFrame;
  1598.         if ContinuousHistogram then
  1599.             ShowContinuousHistogram;
  1600.     end;
  1601.  
  1602.  
  1603.     procedure DoWait;
  1604.         var
  1605.             seconds: extended;
  1606.             SaveTicks: LongInt;
  1607.             str: str255;
  1608.             theEvent: EventRecord;
  1609.     begin
  1610.         GetLeftParen;
  1611.         seconds := GetExpression;
  1612.         GetRightParen;
  1613.         if Token <> DoneT then begin
  1614.                 SaveTicks := TickCount + round(seconds * 60.0);
  1615.                 repeat
  1616.                     if Digitizing then
  1617.                         DoCapture;
  1618.                     if EventAvail(everyEvent, theEvent) then
  1619.                         ; {Allows background tasks to run}
  1620.                 until (TickCount > SaveTicks) or CommandPeriod;
  1621.             end;
  1622.     end;
  1623.  
  1624.  
  1625.     procedure SetDensitySlice; {LowerLevel,UpperLevel:integer}
  1626.   {Disable density slicing if lower and upper=0 and enable it up lower and upper=255}
  1627.         var
  1628.             sStart, sEnd: integer;
  1629.     begin
  1630.         GetLeftParen;
  1631.         sStart := GetInteger;
  1632.         RangeCheck(sStart);
  1633.         GetComma;
  1634.         sEnd := GetInteger;
  1635.         RangeCheck(sEnd);
  1636.         GetRightParen;
  1637.         if Token <> DoneT then begin
  1638.                 DisableDensitySlice;
  1639.                 DisableThresholding;
  1640.                 if (sEnd < sStart) or ((sStart = 0) and (sEnd = 0)) then
  1641.                     exit(SetDensitySlice);
  1642.                 if not ((sStart = 255) and (sEnd = 255)) then begin
  1643.                         SliceStart := sStart;
  1644.                         SliceEnd := sEnd;
  1645.                         if SliceStart < 1 then
  1646.                             SliceStart := 1;
  1647.                         if SliceEnd > 254 then
  1648.                             SliceEnd := 254;
  1649.                     end;
  1650.                 EnableDensitySlice;
  1651.             end;
  1652.     end;
  1653.  
  1654.  
  1655.     procedure SetColor;
  1656.         var
  1657.             index: integer;
  1658.             SaveCommand: CommandType;
  1659.     begin
  1660.         SaveCommand := MacroCommand;
  1661.         GetLeftParen;
  1662.         index := GetInteger;
  1663.         GetRightParen;
  1664.         RangeCheck(index);
  1665.         if Token <> DoneT then begin
  1666.                 if SaveCommand = SetForeC then
  1667.                     SetForegroundColor(index)
  1668.                 else
  1669.                     SetBackgroundColor(index);
  1670.             end;
  1671.     end;
  1672.  
  1673.  
  1674.     procedure DoConstantArithmetic;
  1675.         var
  1676.             constant: extended;
  1677.             SaveCommand: CommandType;
  1678.     begin
  1679.         SaveCommand := MacroCommand;
  1680.         GetLeftParen;
  1681.         constant := GetExpression;
  1682.         GetRightParen;
  1683.         if token <> DoneT then
  1684.             case SaveCommand of
  1685.                 AddConstC: 
  1686.                     DoArithmetic(AddItem, constant);
  1687.                 MulConstC: 
  1688.                     DoArithmetic(MultiplyItem, constant);
  1689.             end;
  1690.     end;
  1691.  
  1692.  
  1693.     procedure GetNextWindow;
  1694.         var
  1695.             n: integer;
  1696.     begin
  1697.         n := info^.PicNum + 1;
  1698.         if n > nPics then
  1699.             n := 1;
  1700.         StopDigitizing;
  1701.         SaveRoi;
  1702.         DisableDensitySlice;
  1703.         SelectWindow(PicWindow[n]);
  1704.         Info := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1705.         ActivateWindow;
  1706.         GenerateValues;
  1707.         LoadLUT(info^.cTable);
  1708.         UpdatePicWindow;
  1709.     end;
  1710.  
  1711.  
  1712.     procedure DoRevert;
  1713.     begin
  1714.         if info^.revertable then begin
  1715.                 RevertToSaved;
  1716.                 UpdatePicWindow;
  1717.             end
  1718.         else
  1719.             MacroError('Unable to revert');
  1720.     end;
  1721.  
  1722.  
  1723.     procedure MakeRoi;
  1724.         var
  1725.             Left, Top, Width, Height: integer;
  1726.             SaveCommand: CommandType;
  1727.     begin
  1728.         SaveCommand := MacroCommand;
  1729.         GetLeftParen;
  1730.         left := GetInteger;
  1731.         GetComma;
  1732.         top := GetInteger;
  1733.         GetComma;
  1734.         width := GetInteger;
  1735.         if width < 1 then
  1736.             width := 1;
  1737.         GetComma;
  1738.         height := GetInteger;
  1739.         if height < 1 then
  1740.             height := 1;
  1741.         GetRightParen;
  1742.         KillRoi;
  1743.         if token <> DoneT then
  1744.             with Info^ do begin
  1745.                     StopDigitizing;
  1746.                     if SaveCommand = MakeOvalC then
  1747.                         RoiType := OvalRoi
  1748.                     else
  1749.                         RoiType := RectRoi;
  1750.                     SetRect(RoiRect, left, top, left + width, top + height);
  1751.                     MakeRegion;
  1752.                     SetupUndo;
  1753.                     RoiShowing := true;
  1754.                 end;
  1755.     end;
  1756.  
  1757.  
  1758.     procedure MoveRoi;
  1759.         var
  1760.             DeltaH, DeltaV: integer;
  1761.     begin
  1762.         GetLeftParen;
  1763.         DeltaH := GetInteger;
  1764.         GetComma;
  1765.         DeltaV := GetInteger;
  1766.         GetRightParen;
  1767.         with info^ do begin
  1768.                 if not RoiShowing then begin
  1769.                         MacroError('No Selection');
  1770.                         exit(MoveRoi);
  1771.                     end;
  1772.                 OffsetRgn(roiRgn, DeltaH, DeltaV);
  1773.                 RoiRect := roiRgn^^.rgnBBox;
  1774.             end;
  1775.     end;
  1776.  
  1777.  
  1778.     procedure InsetRoi;
  1779.         var
  1780.             delta: integer;
  1781.     begin
  1782.         GetLeftParen;
  1783.         delta := GetInteger;
  1784.         GetRightParen;
  1785.         with info^ do begin
  1786.                 if not RoiShowing then begin
  1787.                         MacroError('No Selection');
  1788.                         exit(InsetRoi);
  1789.                     end;
  1790.                 InsetRgn(roiRgn, delta, delta);
  1791.                 RoiRect := roiRgn^^.rgnBBox;
  1792.             end;
  1793.     end;
  1794.  
  1795.  
  1796.     procedure DoMoveTo; {(x,y:integer)}
  1797.     begin
  1798.         GetLeftParen;
  1799.         CurrentX := GetInteger;
  1800.         GetComma;
  1801.         CurrentY := GetInteger;
  1802.         GetRightParen;
  1803.         InsertionPoint.h := CurrentX;
  1804.         InsertionPoint.v := CurrentY + 4;
  1805.     end;
  1806.  
  1807.  
  1808.     procedure DoDrawtext (str: str255; EndOfLine: boolean);
  1809.     begin
  1810.         if info <> NoInfo then begin
  1811.                 KillRoi;
  1812.                 DrawTextString(str, InsertionPoint, TextJust);
  1813.                 if EndOfLine then begin
  1814.                         CurrentY := CurrentY + CurrentSize;
  1815.                         InsertionPoint.h := CurrentX;
  1816.                         InsertionPoint.v := CurrentY + 4;
  1817.                     end;
  1818.             end;
  1819.     end;
  1820.  
  1821.  
  1822.     procedure DrawNumber;
  1823.         var
  1824.             n: extended;
  1825.             str: str255;
  1826.             fwidth: integer;
  1827.     begin
  1828.         GetLeftParen;
  1829.         n := GetExpression;
  1830.         GetRightParen;
  1831.         if token <> DoneT then begin
  1832.                 if n = trunc(n) then
  1833.                     fwidth := 0
  1834.                 else
  1835.                     fwidth := precision;
  1836.                 RealToString(n, 1, fwidth, str);
  1837.                 DoDrawText(str, true);
  1838.             end;
  1839.     end;
  1840.  
  1841.  
  1842.     procedure SetFont;
  1843.         var
  1844.             FontName: str255;
  1845.             id: integer;
  1846.     begin
  1847.         FontName := GetStringArg;
  1848.         if Token <> DoneT then begin
  1849.                 GetFNum(FontName, id);
  1850.                 if id = 0 then
  1851.                     MacroError('Font not available')
  1852.                 else
  1853.                     CurrentFontID := id;
  1854.             end;
  1855.     end;
  1856.  
  1857.  
  1858.     procedure SetFontSize;
  1859.         var
  1860.             size: integer;
  1861.     begin
  1862.         GetLeftParen;
  1863.         Size := GetInteger;
  1864.         GetRightParen;
  1865.         if (size < 6) or (size > 720) then
  1866.             MacroError('Argument out of range');
  1867.         if Token <> DoneT then
  1868.             CurrentSize := size;
  1869.     end;
  1870.  
  1871.  
  1872.     procedure SetText;
  1873.         var
  1874.             Attributes: str255;
  1875.     begin
  1876.         Attributes := GetStringArg;
  1877.         if Token <> DoneT then begin
  1878.                 MakeLowerCase(Attributes);
  1879.                 if pos('with', Attributes) <> 0 then
  1880.                     TextBack := WithBack;
  1881.                 if pos('no', Attributes) <> 0 then
  1882.                     TextBack := NoBack;
  1883.                 if pos('left', Attributes) <> 0 then
  1884.                     TextJust := teJustLeft;
  1885.                 if pos('center', Attributes) <> 0 then
  1886.                     TextJust := teJustCenter;
  1887.                 if pos('right', Attributes) <> 0 then
  1888.                     TextJust := teJustRight;
  1889.                 CurrentStyle := [];
  1890.                 if pos('bold', Attributes) <> 0 then
  1891.                     CurrentStyle := CurrentStyle + [Bold];
  1892.                 if pos('italic', Attributes) <> 0 then
  1893.                     CurrentStyle := CurrentStyle + [Italic];
  1894.                 if pos('underline', Attributes) <> 0 then
  1895.                     CurrentStyle := CurrentStyle + [Underline];
  1896.                 if pos('outline', Attributes) <> 0 then
  1897.                     CurrentStyle := CurrentStyle + [Outline];
  1898.                 if pos('shadow', Attributes) <> 0 then
  1899.                     CurrentStyle := CurrentStyle + [Shadow];
  1900.             end;
  1901.     end;
  1902.  
  1903.  
  1904.     procedure DoPutMessage;
  1905.         var
  1906.             str: str255;
  1907.     begin
  1908.         GetArguments(str);
  1909.         if Token <> DoneT then
  1910.             PutMessage(str)
  1911.     end;
  1912.  
  1913.  
  1914.     function GetVar: integer;
  1915.     begin
  1916.         GetVar := 0;
  1917.         GetToken;
  1918.         if token <> Variable then
  1919.             MacroError('Variable expected')
  1920.         else
  1921.             GetVar := TokenStackLoc;
  1922.     end;
  1923.  
  1924.  
  1925.     procedure GetPicSize;  {(width,height)}
  1926.         var
  1927.             loc1, loc2: integer;
  1928.     begin
  1929.         GetLeftParen;
  1930.         loc1 := GetVar;
  1931.         GetComma;
  1932.         loc2 := GetVar;
  1933.         GetRightParen;
  1934.         if Token <> DoneT then
  1935.             with MacrosP^ do
  1936.                 if info = NoInfo then begin
  1937.                         stack[loc1].value := 0.0;
  1938.                         stack[loc2].value := 0.0;
  1939.                     end
  1940.                 else
  1941.                     with info^ do begin
  1942.                             stack[loc1].value := PixelsPerLine;
  1943.                             stack[loc2].value := nLines;
  1944.                         end;
  1945.     end;
  1946.  
  1947.  
  1948.     procedure GetRoi;  {(hloc,vloc,width,height)}
  1949.         var
  1950.             loc1, loc2, loc3, loc4: integer;
  1951.     begin
  1952.         GetLeftParen;
  1953.         loc1 := GetVar;
  1954.         GetComma;
  1955.         loc2 := GetVar;
  1956.         GetComma;
  1957.         loc3 := GetVar;
  1958.         GetComma;
  1959.         loc4 := GetVar;
  1960.         GetRightParen;
  1961.         if Token <> DoneT then
  1962.             with MacrosP^, Info^ do
  1963.                 if RoiShowing then
  1964.                     with RoiRect do begin
  1965.                             stack[loc1].value := left;
  1966.                             stack[loc2].value := top;
  1967.                             stack[loc3].value := right - left;
  1968.                             stack[loc4].value := bottom - top;
  1969.                         end
  1970.                 else begin
  1971.                         stack[loc1].value := 0.0;
  1972.                         stack[loc2].value := 0.0;
  1973.                         stack[loc3].value := 0.0;
  1974.                         stack[loc4].value := 0.0;
  1975.                     end;
  1976.     end;
  1977.  
  1978.  
  1979.     procedure CaptureOneFrame;
  1980.     begin
  1981.         if FrameGrabber = noFrameGrabber then
  1982.             MacroError('Frame grabber not installed')
  1983.         else begin
  1984.                 StartDigitizing;
  1985.                 CaptureAndDisplayFrame;
  1986.                 StopDigitizing;
  1987.             end;
  1988.     end;
  1989.  
  1990.  
  1991.     procedure DoMakeNewWindow; {(name:str255)}
  1992.         var
  1993.             name: str255;
  1994.     begin
  1995.         GetArguments(name);
  1996.         if token <> DoneT then
  1997.             if (NewPicWidth * NewPicHeight) > UndoBufSize then
  1998.                 MacroError('New window larger than Undo buffer')
  1999.             else if not NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2000.                 MacroError('Out of memory');
  2001.     end;
  2002.  
  2003.  
  2004.     procedure DoSetPalette;
  2005.         var
  2006.             PaletteType: str255;
  2007.             ok, OptionalArgument: boolean;
  2008.             nExtra: LongInt;
  2009.     begin
  2010.         GetLeftParen;
  2011.         PaletteType := GetString;
  2012.         GetToken;
  2013.         OptionalArgument := token <> RightParen;
  2014.         PutTokenBack;
  2015.         if OptionalArgument then begin
  2016.                 GetComma;
  2017.                 nExtra := GetInteger;
  2018.                 if nExtra < 0 then
  2019.                     nExtra := 0;
  2020.                 if nExtra > 6 then
  2021.                     nExtra := 6;
  2022.         end;
  2023.         GetRightParen;
  2024.         if token <> DoneT then begin
  2025.                 MakeLowerCase(PaletteType);
  2026.                 if pos('gray', PaletteType) <> 0 then
  2027.                     ResetGrayMap
  2028.                 else if pos('pseudo', PaletteType) <> 0 then
  2029.                     SwitchColorTables(Pseudo20Item, true)
  2030.                 else if pos('system', PaletteType) <> 0 then
  2031.                     SwitchColorTables(SystemPaletteItem, true)
  2032.                 else if pos('rainbow', PaletteType) <> 0 then
  2033.                     SwitchColorTables(RainbowItem, true)
  2034.                 else if pos('spectrum', PaletteType) <> 0 then
  2035.                     SwitchColorTables(SpectrumItem, true);
  2036.                 if OptionalArgument then begin
  2037.                     nExtraColors := nExtra;
  2038.                     RedrawLUTWindow;
  2039.                 end;
  2040.             end;
  2041.     end;
  2042.  
  2043.  
  2044.     procedure DoOpenImage;
  2045.         var
  2046.             err: OSErr;
  2047.             f: integer;
  2048.             FileFound, result: boolean;
  2049.             fname: str255;
  2050.             SaveCommand: CommandType;
  2051.     begin
  2052.         SaveCommand := MacroCommand;
  2053.         GetArguments(fname);
  2054.         if token <> DoneT then begin
  2055.                 if fname = '' then
  2056.                     fname := DefaultFileName;
  2057.                 err := fsopen(fname, DefaultRefNum, f);
  2058.                 FileFound := err = NoErr;
  2059.                 err := fsclose(f);
  2060.                 if FileFound then
  2061.                     case SaveCommand of
  2062.                         OpenC: 
  2063.                             result := DoOpen(fname, DefaultRefNum);
  2064.                         ImportC: 
  2065.                             result := ImportFile(fname, DefaultRefNum);
  2066.                     end
  2067.                 else
  2068.                     case SaveCommand of
  2069.                         OpenC: 
  2070.                             result := DoOpen('', 0);
  2071.                         ImportC: 
  2072.                             result := ImportFile('', 0);
  2073.                     end;
  2074.                 if result then
  2075.                     UpdatePicWindow
  2076.                 else
  2077.                     token := DoneT;
  2078.             end;
  2079.     end;
  2080.  
  2081.  
  2082.     procedure SetImportAttributes;
  2083.         var
  2084.             Attributes: str255;
  2085.     begin
  2086.         Attributes := GetStringArg;
  2087.         if Token <> DoneT then begin
  2088.                 MakeLowerCase(Attributes);
  2089.                 WhatToImport := ImportTIFF;
  2090.                 ImportCustomDepth := EightBits;
  2091.                 ImportSwapBytes := false;
  2092.                 ImportCalibrate := false;
  2093.                 ImportAll := false;
  2094.                 ImportAutoScale := true;
  2095.                 ImportInvert := false;
  2096.                 if pos('dicom', Attributes) <> 0 then
  2097.                     WhatToImport := ImportDICOM;
  2098.                 if pos('mcid', Attributes) <> 0 then
  2099.                     WhatToImport := ImportMCID;
  2100.                 if pos('look', Attributes) <> 0 then
  2101.                     WhatToImport := ImportLUT;
  2102.                 if pos('palette', Attributes) <> 0 then
  2103.                     WhatToImport := ImportLUT;
  2104.                 if pos('text', Attributes) <> 0 then
  2105.                     WhatToImport := ImportText;
  2106.                 if pos('custom', Attributes) <> 0 then
  2107.                     WhatToImport := ImportCustom;
  2108.                 if (pos('8', Attributes) <> 0) or (pos('eight', Attributes) <> 0) then begin
  2109.                         ImportCustomDepth := EightBits;
  2110.                         WhatToImport := ImportCustom;
  2111.                     end;
  2112.                 if (pos('signed', Attributes) <> 0) then begin
  2113.                         ImportCustomDepth := SixteenBitsSigned;
  2114.                         WhatToImport := ImportCustom;
  2115.                     end;
  2116.                 if (pos('unsigned', Attributes) <> 0) then begin
  2117.                         ImportCustomDepth := SixteenBitsUnsigned;
  2118.                         WhatToImport := ImportCustom;
  2119.                     end;
  2120.                 if (pos('swap', Attributes) <> 0) then
  2121.                     ImportSwapBytes := true;
  2122.                 if (pos('calibrate', Attributes) <> 0) then
  2123.                     ImportCalibrate := true;
  2124.                 if (pos('fixed', Attributes) <> 0) then
  2125.                     ImportAutoScale := false;
  2126.                 if (pos('all', Attributes) <> 0) then
  2127.                     ImportAll := true;
  2128.                 if (pos('invert', Attributes) <> 0) then
  2129.                     ImportInvert := true;
  2130.             end;
  2131.     end;
  2132.  
  2133.  
  2134.     procedure SetImportMinMax; {(min,max:integer)}
  2135.         var
  2136.             TempMin, TempMax: extended;
  2137.     begin
  2138.         GetLeftParen;
  2139.         TempMin := GetExpression;
  2140.         GetComma;
  2141.         TempMax := GetExpression;
  2142.         GetRightParen;
  2143.         if Token <> DoneT then begin
  2144.                 ImportAutoScale := false;
  2145.                 ImportMin := TempMin;
  2146.                 ImportMax := TempMax;
  2147.             end;
  2148.     end;
  2149.  
  2150.  
  2151.     procedure SetCustomImport; {(width,height,offset[,nslices]:integer)}
  2152.         var
  2153.             width, height, nSlices: integer;
  2154.             offset: LongInt;
  2155.     begin
  2156.         GetLeftParen;
  2157.         width := GetInteger;
  2158.         GetComma;
  2159.         height := GetInteger;
  2160.         GetComma;
  2161.         offset := GetInteger;
  2162.         GetToken;
  2163.         if token = comma then
  2164.             nSlices := GetInteger
  2165.         else begin
  2166.                 PutTokenBack;
  2167.                 nSlices := 1
  2168.             end;
  2169.         GetRightParen;
  2170.         if (width < 0) or (width > MaxPicSize) or (height < 0) or (offset < 0) or (nSlices < 1) or (nSlices > MaxSlices) then
  2171.             MacroError('Argument out of range');
  2172.         if Token <> DoneT then begin
  2173.                 ImportCustomWidth := width;
  2174.                 ImportCustomHeight := height;
  2175.                 ImportCustomOffset := offset;
  2176.                 ImportCustomSlices := nSlices;
  2177.                 WhatToImport := ImportCustom;
  2178.             end;
  2179.     end;
  2180.  
  2181.  
  2182.     procedure SelectImage (id: integer);
  2183.     begin
  2184.         StopDigitizing;
  2185.         SaveRoi;
  2186.         DisableDensitySlice;
  2187.         SelectWindow(PicWindow[id]);
  2188.         Info := pointer(WindowPeek(PicWindow[id])^.RefCon);
  2189.         ActivateWindow;
  2190.         GenerateValues;
  2191.         LoadLUT(info^.cTable);
  2192.         UpdatePicWindow;
  2193.     end;
  2194.  
  2195.  
  2196.     procedure SelectPic; {(PicN:integer)}
  2197.         var
  2198.             PicN, i: integer;
  2199.             SaveCommand: CommandType;
  2200.     begin
  2201.         SaveCommand := MacroCommand;
  2202.         GetLeftParen;
  2203.         PicN := GetInteger;
  2204.         GetRightParen;
  2205.         i := 0;
  2206.         while (PicN < 0) and (i < nPics) do begin
  2207.                 i := i + 1;
  2208.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  2209.                     PicN := i;
  2210.             end;
  2211.         if (PicN < 1) or (PicN > nPics) then
  2212.             MacroError('Specified image does not exist');
  2213.         if Token <> DoneT then begin
  2214.                 if SaveCommand = SelectPicC then
  2215.                     SelectImage(PicN)
  2216.                 else begin
  2217.                         StopDigitizing;
  2218.                         DisableDensitySlice;
  2219.                         Info := pointer(WindowPeek(PicWindow[PicN])^.RefCon);
  2220.                     end;
  2221.             end;
  2222.     end;
  2223.  
  2224.  
  2225.     procedure SetPicName;  {(name:string)}
  2226.         var
  2227.             n, i: LongInt;
  2228.             isInteger: boolean;
  2229.             name: str255;
  2230.     begin
  2231.         GetArguments(name);
  2232.         if Token <> DoneT then begin
  2233.                 with info^ do begin
  2234.                         title := name;
  2235.                         if PictureType <> FrameGrabberType then
  2236.                             PictureType := NewPicture;
  2237.                         UpdateWindowsMenuItem;
  2238.                         UpdateTitleBar;
  2239.                     end;
  2240.             end;
  2241.     end;
  2242.  
  2243.  
  2244.     procedure SetNewSize; {(width,height:integer)}
  2245.         var
  2246.             TempWidth, TempHeight: integer;
  2247.     begin
  2248.         GetLeftParen;
  2249.         TempWidth := GetInteger;
  2250.         GetComma;
  2251.         TempHeight := GetInteger;
  2252.         GetRightParen;
  2253.         if Token <> DoneT then begin
  2254.                 NewPicWidth := TempWidth;
  2255.                 NewPicHeight := TempHeight;
  2256.                 if NewPicWidth > MaxPicSize then
  2257.                     NewPicWidth := MaxPicSize;
  2258.                 if NewPicWidth < 8 then
  2259.                     NewPicWidth := 8;
  2260.                 if NewPicHeight < 1 then
  2261.                     NewPicHeight := 1;
  2262.                 if NewPicHeight > MaxPicSize then
  2263.                     NewPicHeight := MaxPicSize;
  2264.             end;
  2265.     end;
  2266.  
  2267.  
  2268.     procedure DoSaveAs;
  2269.         var
  2270.             name: str255;
  2271.             RefNum: integer;
  2272.             HasArgs: boolean;
  2273.     begin
  2274.         name := info^.title;
  2275.         if (name = 'Untitled') or (name = 'Camera') then
  2276.             name := '';
  2277.         GetToken;
  2278.         HasArgs := token = LeftParen;
  2279.         PutTokenBack;
  2280.         if HasArgs then
  2281.             GetArguments(name);
  2282.         if token <> DoneT then begin
  2283.                 StopDigitizing;
  2284.                 if nSaves = 0 then
  2285.                     RefNum := 0
  2286.                 else
  2287.                     RefNum := DefaultRefNum;
  2288.                 case CurrentWindow of
  2289.                     TextKind: 
  2290.                         if pos(':', name) <> 0 then
  2291.                             SaveTextUsingPath(name)
  2292.                         else
  2293.                             SaveTextAs;
  2294.                     ResultsKind: 
  2295.                         Export('', RefNum);
  2296.                     otherwise begin
  2297.                             if info <> NoInfo then
  2298.                                 SaveAs(name, RefNum)
  2299.                             else
  2300.                                 MacroError(NoImageOpen);
  2301.                         end;
  2302.                 end;
  2303.                 nSaves := nSaves + 1;
  2304.             end;
  2305.     end;
  2306.  
  2307.  
  2308.     procedure DoSave;
  2309.         var
  2310.             kind: integer;
  2311.     begin
  2312.         StopDigitizing;
  2313.         kind := CurrentWindow;
  2314.         if (kind = PicKind) or (kind = TextKind) or (Kind = ResultsKind) then
  2315.             SaveFile
  2316.         else
  2317.             MacroError('Nothing to save');
  2318.     end;
  2319.  
  2320.  
  2321.     procedure DoExport;
  2322.         var
  2323.             name: str255;
  2324.             RefNum: integer;
  2325.             HasArgs: boolean;
  2326.     begin
  2327.         StopDigitizing;
  2328.         name := info^.title;
  2329.         if (name = 'Untitled') or (name = 'Camera') then
  2330.             name := '';
  2331.         GetToken;
  2332.         HasArgs := token = LeftParen;
  2333.         PutTokenBack;
  2334.         if HasArgs then
  2335.             GetArguments(name);
  2336.         if nSaves = 0 then
  2337.             RefNum := 0
  2338.         else
  2339.             RefNum := DefaultRefNum;
  2340.         Export(name, RefNum);
  2341.         nSaves := nSaves + 1;
  2342.     end;
  2343.  
  2344.  
  2345.     procedure DoCopyResults;
  2346.         var
  2347.             IgnoreResult: boolean;
  2348.     begin
  2349.         if mCount < 1 then
  2350.             MacroError('Copy Results failed')
  2351.         else begin
  2352.                 CopyResults;
  2353.                 IgnoreResult := SystemEdit(3); {Fake Copy needed for MultiFinder}
  2354.             end;
  2355.     end;
  2356.  
  2357.  
  2358.     procedure DisposeAll;
  2359.         var
  2360.             i, ignore: integer;
  2361.     begin
  2362.         StopDigitizing;
  2363.         for i := nPics downto 1 do begin
  2364.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  2365.                 ignore := CloseAWindow(info^.wptr);
  2366.             end;
  2367.     end;
  2368.  
  2369.  
  2370.     procedure DoDuplicate;
  2371.         var
  2372.             str: str255;
  2373.     begin
  2374.         GetArguments(str);
  2375.         if token <> DoneT then
  2376.             if not Duplicate(str, false) then
  2377.                 token := DoneT
  2378.             else
  2379.                 UpdatePicWindow;
  2380.     end;
  2381.  
  2382.  
  2383.     procedure DoLineTo; {(x,y:integer)}
  2384.         var
  2385.             x, y: integer;
  2386.             p1, p2: point;
  2387.     begin
  2388.         GetLeftParen;
  2389.         p2.h := GetInteger;
  2390.         GetComma;
  2391.         p2.v := GetInteger;
  2392.         GetRightParen;
  2393.         if token <> DoneT then begin
  2394.                 KillRoi;
  2395.                 p1.h := CurrentX;
  2396.                 p1.v := CurrentY;
  2397.                 CurrentX := p2.h;
  2398.                 CurrentY := p2.v;
  2399.                 OffscreenToScreen(p1);
  2400.                 OffscreenToScreen(p2);
  2401.                 DrawObject(LineObj, p1, p2);
  2402.             end;
  2403.     end;
  2404.  
  2405.  
  2406.     procedure DoGetLine;  {(var x1,y1,x2,y2:real; LineWidth:integer)}
  2407.         var
  2408.             loc1, loc2, loc3, loc4, loc5: integer;
  2409.             x1, y1, x2, y2: extended;
  2410.     begin
  2411.         GetLeftParen;
  2412.         loc1 := GetVar;
  2413.         GetComma;
  2414.         loc2 := GetVar;
  2415.         GetComma;
  2416.         loc3 := GetVar;
  2417.         GetComma;
  2418.         loc4 := GetVar;
  2419.         GetComma;
  2420.         loc5 := GetVar;
  2421.         GetRightParen;
  2422.         if Token <> DoneT then
  2423.             with MacrosP^, info^ do begin
  2424.                     GetLoi(x1, y1, x2, y2);
  2425.                     if RoiShowing and (RoiType = LineRoi) then
  2426.                         stack[loc1].value := x1
  2427.                     else
  2428.                         stack[loc1].value := -1;
  2429.                     stack[loc2].value := y1;
  2430.                     stack[loc3].value := x2;
  2431.                     stack[loc4].value := y2;
  2432.                     stack[loc5].value := LineWidth;
  2433.                 end;
  2434.     end;
  2435.  
  2436.  
  2437.     procedure DoScaleAndRotate; {(hscale,vscale,angle:real)}
  2438.         var
  2439.             SaveCommand: CommandType;
  2440.     begin
  2441.         SaveCommand := MacroCommand;
  2442.         GetLeftParen;
  2443.         rsHScale := GetExpression;
  2444.         GetComma;
  2445.         rsVScale := GetExpression;
  2446.         if SaveCommand <> ScaleSelectionC then begin
  2447.                 GetComma;
  2448.                 rsAngle := GetExpression;
  2449.             end;
  2450.         GetRightParen;
  2451.         if token <> DoneT then begin
  2452.                 if SaveCommand = ScaleSelectionC then begin
  2453.                         rsMethod := NearestNeighbor;
  2454.                         rsCreateNewWindow := false;
  2455.                         rsAngle := 0.0;
  2456.                     end;
  2457.                 ScaleAndRotate;
  2458.             end;
  2459.     end;
  2460.  
  2461.  
  2462.     procedure SetPlotScale; {(min,max:integer)}
  2463.         var
  2464.             min, max: extended;
  2465.     begin
  2466.         GetLeftParen;
  2467.         min := GetExpression;
  2468.         GetComma;
  2469.         max := GetExpression;
  2470.         GetRightParen;
  2471.         if info^.fit = uncalibrated then begin
  2472.                 RangeCheck(trunc(min));
  2473.                 RangeCheck(trunc(max));
  2474.             end;
  2475.         if token <> DoneT then begin
  2476.                 AutoScalePlots := (min = 0.0) and (max = 0.0);
  2477.                 ProfilePlotMin := min;
  2478.                 ProfilePlotMax := max;
  2479.             end;
  2480.     end;
  2481.  
  2482.  
  2483.     procedure SetPlotDimensions; {(width,height:integer)}
  2484.         var
  2485.             width, height: integer;
  2486.     begin
  2487.         GetLeftParen;
  2488.         width := GetInteger;
  2489.         GetComma;
  2490.         height := GetInteger;
  2491.         GetRightParen;
  2492.         if token <> DoneT then begin
  2493.                 FixedSizePlot := not ((width = 0) and (height = 0));
  2494.                 ProfilePlotWidth := width;
  2495.                 ProfilePlotHeight := height;
  2496.             end;
  2497.     end;
  2498.  
  2499.  
  2500.     procedure GetResults;  {(var n,mean,mode,min,max:real)}
  2501.         var
  2502.             loc1, loc2, loc3, loc4, loc5: integer;
  2503.     begin
  2504.         GetLeftParen;
  2505.         loc1 := GetVar;
  2506.         GetComma;
  2507.         loc2 := GetVar;
  2508.         GetComma;
  2509.         loc3 := GetVar;
  2510.         GetComma;
  2511.         loc4 := GetVar;
  2512.         GetComma;
  2513.         loc5 := GetVar;
  2514.         GetRightParen;
  2515.         if mCount = 0 then
  2516.             MacroError('No results');
  2517.         if Token <> DoneT then
  2518.             with MacrosP^, results do begin
  2519.                     stack[loc1].value := PixelCount^[mCount];
  2520.                     stack[loc2].value := UncalibratedMean;
  2521.                     stack[loc3].value := imode;
  2522.                     stack[loc4].value := MinIndex;
  2523.                     stack[loc5].value := MaxIndex;
  2524.                 end;
  2525.     end;
  2526.  
  2527.  
  2528.     procedure DoPasteOperation;
  2529.     begin
  2530.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  2531.                 MacroError('Not pasting');
  2532.                 exit(DoPasteOperation);
  2533.             end;
  2534.         if MacroCommand in [AddC, SubC, MulC, DivC] then begin
  2535.                 case MacroCommand of
  2536.                     AddC: 
  2537.                         CurrentOp := AddOp;
  2538.                     SubC: 
  2539.                         CurrentOp := SubtractOp;
  2540.                     MulC: 
  2541.                         CurrentOp := MultiplyOp;
  2542.                     DivC: 
  2543.                         CurrentOp := DivideOp;
  2544.                 end;
  2545.                 DoPasteMath;
  2546.                 exit(DoPasteOperation);
  2547.             end;
  2548.         SetForegroundColor(BlackIndex);
  2549.         SetBackGroundColor(WhiteIndex);
  2550.         case MacroCommand of
  2551.             CopyModeC: 
  2552.                 SetPasteMode(CopyModeItem);
  2553.             AndC: 
  2554.                 SetPasteMode(AndItem);
  2555.             OrC: 
  2556.                 SetPasteMode(OrItem);
  2557.             XorC: 
  2558.                 SetPasteMode(XorItem);
  2559.             ReplaceC: 
  2560.                 SetPasteMode(ReplaceItem);
  2561.             BlendC: 
  2562.                 SetPasteMode(BlendItem);
  2563.         end;
  2564.         if OptionKeyWasDown then begin
  2565.                 if PasteControl <> nil then
  2566.                     DrawPasteControl;
  2567.             end
  2568.         else
  2569.             KillRoi;
  2570.     end;
  2571.  
  2572.  
  2573.     procedure SetWidth; {(width:integer)}
  2574.         var
  2575.             width: integer;
  2576.     begin
  2577.         GetLeftParen;
  2578.         width := GetInteger;
  2579.         GetRightParen;
  2580.         if (Token <> DoneT) and (width > 0) then begin
  2581.                 LineWidth := width;
  2582.                 ShowLIneWidth;
  2583.             end;
  2584.     end;
  2585.  
  2586.  
  2587.     function GetMType (index: integer): MeasurementTypes;
  2588.     begin
  2589.         case index of
  2590.             0: 
  2591.                 GetMType := AreaM;
  2592.             1: 
  2593.                 GetMType := MeanM;
  2594.             2: 
  2595.                 GetMType := StdDevM;
  2596.             3: 
  2597.                 GetMType := xyLocM;
  2598.             4: 
  2599.                 GetMType := ModeM;
  2600.             5: 
  2601.                 GetMType := LengthM;
  2602.             6: 
  2603.                 GetMType := MajorAxisM;
  2604.             7: 
  2605.                 GetMType := MinorAxisM;
  2606.             8: 
  2607.                 GetMType := AngleM;
  2608.             9: 
  2609.                 GetMType := IntDenM;
  2610.             10: 
  2611.                 GetMType := MinMaxM;
  2612.             11: 
  2613.                 GetMType := User1M;
  2614.             12: 
  2615.                 GetMType := User2M;
  2616.         end;
  2617.     end;
  2618.  
  2619.  
  2620.     procedure SetPrecision; {(DigitsRightofDecimalPoint[,FieldWidth]:integer)}
  2621.         var
  2622.             digits, width: LongInt;
  2623.     begin
  2624.         GetLeftParen;
  2625.         digits := GetInteger;
  2626.         GetToken;
  2627.         if token = comma then
  2628.             width := GetInteger
  2629.         else
  2630.             PutTokenBack;
  2631.         GetRightParen;
  2632.         if Token <> DoneT then begin
  2633.                 if (digits >= 0) and (digits <= 12) then
  2634.                     precision := digits;
  2635.                 if (width >= 1) and (width <= 18) then
  2636.                     FieldWidth := width;
  2637.             end;
  2638.     end;
  2639.  
  2640.  
  2641.     procedure SetParticleSize; {(min,max:LongInt)}
  2642.         var
  2643.             min, max: LongInt;
  2644.     begin
  2645.         GetLeftParen;
  2646.         min := GetInteger;
  2647.         GetComma;
  2648.         max := GetInteger;
  2649.         GetRightParen;
  2650.         if Token <> DoneT then begin
  2651.                 MinParticleSize := min;
  2652.                 MaxParticleSize := max;
  2653.             end;
  2654.     end;
  2655.  
  2656.  
  2657.     procedure SetThreshold; {(level:integer)}
  2658.         var
  2659.             level: LongInt;
  2660.     begin
  2661.         GetLeftParen;
  2662.         level := GetInteger;
  2663.         GetRightParen;
  2664.         if level = -1 then begin
  2665.                 DisableThresholding;
  2666.                 exit(SetThreshold);
  2667.             end;
  2668.         RangeCheck(level);
  2669.         if Token <> DoneT then
  2670.             EnableThresholding(level);
  2671.     end;
  2672.  
  2673.  
  2674.     procedure DrawPixel (h, v, value: integer);
  2675.   {Draws a pixel on the screen in the current foreground color.}
  2676.     begin
  2677.         SetPort(info^.wptr);
  2678.         PenNormal;
  2679.         SetFColor(value);
  2680.         PenSize(1, 1);
  2681.         MoveTo(h, v);
  2682.         LineTo(h, v);
  2683.     end;
  2684.  
  2685.  
  2686.     procedure DoPutPixel; {(hloc,vloc, value:integer)}
  2687.         var
  2688.             hloc, vloc: LongInt;
  2689.             value: integer;
  2690.             MaskRect: rect;
  2691.     begin
  2692.         GetLeftParen;
  2693.         hloc := GetInteger;
  2694.         GetComma;
  2695.         vloc := GetInteger;
  2696.         GetComma;
  2697.         value := GetInteger;
  2698.         GetRightParen;
  2699.         if (Token <> DoneT) and (info <> NoInfo) then begin
  2700.                 KillRoi;
  2701.                 PutPixel(hloc, vloc, value);
  2702.                 if info^.magnification = 1.0 then
  2703.                     DrawPixel(hloc, vloc, value)
  2704.                 else begin
  2705.                     SetRect(MaskRect, hloc, vloc, hloc + 1, vloc + 1);
  2706.                     UpdateScreen(MaskRect);
  2707.                 end;
  2708.                 info^.changes := true;
  2709.             end;
  2710.     end;
  2711.  
  2712.  
  2713.     procedure CloseWindow;
  2714.         var
  2715.             OldPicNum, NewPicNum, ignore: integer;
  2716.     begin
  2717.         if CurrentWindow <> PicKind then begin
  2718.                 ignore := CloseAWindow(CurrentWPtr);
  2719.                 exit(CloseWindow);
  2720.             end;
  2721.         if info = NoInfo then begin
  2722.                 MacroError(NoImageOpen);
  2723.                 exit(CloseWindow);
  2724.             end;
  2725.         StopDigitizing;
  2726.         SaveRoi;
  2727.         with info^ do begin
  2728.                 OldPicNum := PicNum;
  2729.                 ignore := CloseAWindow(wptr);
  2730.             end;
  2731.         if nPics >= 1 then begin
  2732.                 NewPicNum := OldPicNum - 1;
  2733.                 if NewPicNum < 1 then
  2734.                     NewPicNum := 1;
  2735.                 SelectImage(NewPicNum);
  2736.             end;
  2737.     end;
  2738.  
  2739.  
  2740.     procedure SetScaling;
  2741.         var
  2742.             ScalingOptions: str255;
  2743.             ok: boolean;
  2744.     begin
  2745.         ScalingOptions := GetStringArg;
  2746.         if token <> DoneT then begin
  2747.                 MakeLowerCase(ScalingOptions);
  2748.                 rsInteractive := false;
  2749.                 if pos('bilinear', ScalingOptions) <> 0 then
  2750.                     rsMethod := Bilinear;
  2751.                 if pos('nearest', ScalingOptions) <> 0 then
  2752.                     rsMethod := NearestNeighbor;
  2753.                 if pos('new', ScalingOptions) <> 0 then
  2754.                     rsCreateNewWindow := true;
  2755.                 if pos('same', ScalingOptions) <> 0 then
  2756.                     rsCreateNewWindow := false;
  2757.                 if pos('interactive', ScalingOptions) <> 0 then
  2758.                     rsInteractive := true;
  2759.             end;
  2760.     end;
  2761.  
  2762.  
  2763.     procedure DoChangeValues; {(v1,v2,v3:integer)}
  2764.         var
  2765.             v1, v2, v3: integer;
  2766.     begin
  2767.         GetLeftParen;
  2768.         v1 := GetInteger;
  2769.         GetComma;
  2770.         v2 := GetInteger;
  2771.         GetComma;
  2772.         v3 := GetInteger;
  2773.         GetRightParen;
  2774.         RangeCheck(v1);
  2775.         RangeCheck(v2);
  2776.         RangeCheck(v3);
  2777.         if Token <> DoneT then
  2778.             ChangeValues(v1, v2, v3);
  2779.     end;
  2780.  
  2781.  
  2782.     procedure DoGetMouse;  {(var x,y:integer)}
  2783.         var
  2784.             loc1, loc2, sh, sv: integer;
  2785.             loc: point;
  2786.     begin
  2787.         GetLeftParen;
  2788.         loc1 := GetVar;
  2789.         GetComma;
  2790.         loc2 := GetVar;
  2791.         GetRightParen;
  2792.         if Token <> DoneT then
  2793.             with MacrosP^ do begin
  2794.                     SetPort(info^.wptr);
  2795.                     GetMouse(loc);
  2796.                     with loc do begin
  2797.                             sh := h;
  2798.                             sv := v;
  2799.                             ScreenToOffscreen(loc);
  2800.                             if sh < 0 then
  2801.                                 h := sh;
  2802.                             if sv < 0 then
  2803.                                 v := sv;
  2804.                             stack[loc1].value := h;
  2805.                             stack[loc2].value := v;
  2806.                         end;
  2807.                 end;
  2808.     end;
  2809.  
  2810.  
  2811.     procedure DoRotate (cmd: CommandType);
  2812.         var
  2813.             NoBoolean, NewWindow: boolean;
  2814.     begin
  2815.         GetToken;
  2816.         noBoolean := token <> LeftParen;
  2817.         PutTokenBack;
  2818.         if NoBoolean then
  2819.             NewWindow := false
  2820.         else
  2821.             NewWindow := GetBooleanArg;
  2822.         if NewWindow then begin
  2823.                 case cmd of
  2824.                     RotateRC: 
  2825.                         RotateToNewWindow(RotateRight);
  2826.                     RotateLC: 
  2827.                         RotateToNewWindow(RotateLeft)
  2828.                 end;
  2829.                 if not macro then
  2830.                     MacroError('Rotate failed')
  2831.             end
  2832.         else
  2833.             case cmd of
  2834.                 RotateRC: 
  2835.                     FlipOrRotate(RotateRight);
  2836.                 RotateLC: 
  2837.                     FlipOrRotate(RotateLeft)
  2838.             end;
  2839.     end;
  2840.  
  2841.  
  2842.     procedure DoSelectSlice; {(SliceNumber:integer)}
  2843.         var
  2844.             SliceNumber: LongInt;
  2845.             isRoi: boolean;
  2846.             SaveCommand: CommandType;
  2847.     begin
  2848.         SaveCommand := MacroCommand;
  2849.         GetLeftParen;
  2850.         SliceNumber := GetInteger;
  2851.         GetRightParen;
  2852.         with info^, info^.StackInfo^ do begin
  2853.                 if (SliceNumber < 1) or (SliceNumber > nSlices) then
  2854.                     MacroError('Illegal slice number');
  2855.                 if Token <> DoneT then begin
  2856.                         isRoi := RoiShowing;
  2857.                         if isRoi then
  2858.                             KillRoi;
  2859.                         CurrentSlice := SliceNumber;
  2860.                         SelectSlice(CurrentSlice);
  2861.                         if SaveCommand = SelectSliceC then begin
  2862.                                 UpdatePicWindow;
  2863.                                 UpdateTitleBar;
  2864.                             end;
  2865.                         if isRoi then
  2866.                             RestoreRoi;
  2867.                     end;
  2868.             end;
  2869.     end;
  2870.  
  2871.  
  2872.     procedure MakeNewStack; {(name:str255)}
  2873.         var
  2874.             name: str255;
  2875.             aok: boolean;
  2876.     begin
  2877.         GetArguments(name);
  2878.         if token <> DoneT then
  2879.             if (NewPicWidth * NewPicHeight) > UndoBufSize then
  2880.                 MacroError('Stack larger than Undo Buffer')
  2881.             else if NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2882.                 if not MakeStackFromWindow then
  2883.                     MacroError('Out of memory');
  2884.     end;
  2885.  
  2886.  
  2887.     procedure MakeLineRoi; {(x1,y1,x2,y2:real)}
  2888.         var
  2889.             x1, y1, x2, y2: extended;
  2890.     begin
  2891.         GetLeftParen;
  2892.         x1 := GetExpression;
  2893.         GetComma;
  2894.         y1 := GetExpression;
  2895.         GetComma;
  2896.         x2 := GetExpression;
  2897.         GetComma;
  2898.         y2 := GetExpression;
  2899.         GetRightParen;
  2900.         if token <> DoneT then
  2901.             with Info^ do begin
  2902.                     KillRoi;
  2903.                     StopDigitizing;
  2904.                     LX1 := x1;
  2905.                     LY1 := y1;
  2906.                     LX2 := x2;
  2907.                     LY2 := y2;
  2908.                     RoiType := LineRoi;
  2909.                     MakeRegion;
  2910.                     SetupUndo;
  2911.                     RoiShowing := true;
  2912.                 end;
  2913.     end;
  2914.  
  2915.  
  2916.     procedure DoGetTime;
  2917.         var
  2918.             date: DateTimeRec;
  2919.             loc1, loc2, loc3, loc4, loc5, loc6, loc7: integer;
  2920.     begin
  2921.         GetLeftParen;
  2922.         loc1 := GetVar;
  2923.         GetComma;
  2924.         loc2 := GetVar;
  2925.         GetComma;
  2926.         loc3 := GetVar;
  2927.         GetComma;
  2928.         loc4 := GetVar;
  2929.         GetComma;
  2930.         loc5 := GetVar;
  2931.         GetComma;
  2932.         loc6 := GetVar;
  2933.         GetComma;
  2934.         loc7 := GetVar;
  2935.         GetRightParen;
  2936.         if Token <> DoneT then
  2937.             with MacrosP^, info^ do begin
  2938.                     GetTime(date);
  2939.                     with date do begin
  2940.                             stack[loc1].value := year;
  2941.                             stack[loc2].value := month;
  2942.                             stack[loc3].value := day;
  2943.                             stack[loc4].value := hour;
  2944.                             stack[loc5].value := minute;
  2945.                             stack[loc6].value := second;
  2946.                             stack[loc7].value := DayOfWeek;
  2947.                         end;
  2948.                 end;
  2949.     end;
  2950.  
  2951.  
  2952.     function GetStringVar: integer;
  2953.     begin
  2954.         GetStringVar := 0;
  2955.         GetToken;
  2956.         if token <> StringVariable then
  2957.             MacroError('String variable expected')
  2958.         else
  2959.             GetStringVar := TokenStackLoc;
  2960.     end;
  2961.  
  2962.  
  2963.     procedure DoSetScale; {(scale:real; unit:string; [AspectRatio: real])}
  2964.         var
  2965.             id: integer;
  2966.             scale, AspectRatio: extended;
  2967.             str: str255;
  2968.     begin
  2969.         AspectRatio:=0.0;
  2970.         GetLeftParen;
  2971.         scale := GetExpression;
  2972.         GetComma;
  2973.         str := GetString;
  2974.         GetToken;
  2975.         if token=comma
  2976.             then AspectRatio:=GetExpression
  2977.             else PutTokenBack;
  2978.         GetRightParen;
  2979.         if token <> DoneT then
  2980.             with info^ do begin
  2981.                     if str = '' then begin
  2982.                             SetScale; {Display Set Scale dialog box}
  2983.                             exit(DoSetScale);
  2984.                         end;
  2985.                     if scale < 0.0 then begin
  2986.                             MacroError('Scale<0');
  2987.                             exit(DoSetScale);
  2988.                         end;
  2989.                     MakeLowerCase(str);
  2990.                     TruncateString(str, maxUnit);
  2991.                     xUnit := str;
  2992.                     xScale := scale;
  2993.                     yScale := scale;
  2994.                     if AspectRatio>0.0 then begin
  2995.                         PixelAspectRatio:=AspectRatio;
  2996.                         yScale := xScale / PixelAspectRatio;
  2997.                     end else
  2998.                         PixelAspectRatio := 1.0;
  2999.                     SpatiallyCalibrated := (xUnit <> '') and (xUnit <> 'pixel') and (xUnit <> 'pixels') and (xScale <> 0.0);
  3000.                     UpdateTitleBar;
  3001.                 end;
  3002.     end;
  3003.  
  3004.  
  3005.     procedure GetScale;  {(var scale:real; unit:string; [AspectRatio:real])}
  3006.         var
  3007.             loc1, loc2, loc3, index, count: integer;
  3008.             str: str255;
  3009.     begin
  3010.         GetLeftParen;
  3011.         loc1 := GetVar;
  3012.         GetComma;
  3013.         loc2 := GetStringVar;
  3014.         loc3:=0;
  3015.         GetToken;
  3016.         if token=comma
  3017.          then loc3 := GetVar
  3018.          else PutTokenBack;
  3019.         GetRightParen;
  3020.         if Token <> DoneT then
  3021.             with info^, MacrosP^ do
  3022.                 if SpatiallyCalibrated then begin
  3023.                         stack[loc1].value := xScale;
  3024.                         stack[loc2].StringH^^ := xUnit;
  3025.                         if loc3>0 then stack[loc3].value := PixelAspectRatio;
  3026.                     end
  3027.                 else begin
  3028.                         stack[loc1].value := 1.0;
  3029.                         stack[loc2].StringH^^ := 'pixel';
  3030.                         if loc3>0 then stack[loc3].value := 1.0;
  3031.                     end;
  3032.     end;
  3033.  
  3034.  
  3035.     procedure SaveState;
  3036.     begin
  3037.         SaveForeground := ForegroundIndex;
  3038.         SaveBackground := BackgroundIndex;
  3039.         SavePicWidth := NewPicWidth;
  3040.         SavePicHeight := NewPicHeight;
  3041.         SaveMethod := rsMethod;
  3042.         SaveCreate := rsCreateNewWindow;
  3043.         SaveAngle := rsAngle;
  3044.         SaveH := rsHScale;
  3045.         SaveV := rsVScale;
  3046.         SaveInvertY := InvertYCoordinates;
  3047.         SaveScaleArithmetic := ScaleArithmetic;
  3048.         SaveScaleConvolutions := ScaleConvolutions;
  3049.         SaveCurrentFontID:=CurrentFontID;
  3050.         SaveCurrentSize:=CurrentSize;
  3051.         SaveCurrentStyle:=CurrentStyle;
  3052.         SaveTextJust:=TextJust;
  3053.         SaveTextBack:=TextBack;
  3054.     end;
  3055.  
  3056.  
  3057.     procedure RestoreState;
  3058.     begin
  3059.         if SaveForeground = -1 then
  3060.             MacroError('State not saved')
  3061.         else begin
  3062.                 SetForegroundColor(SaveForeground);
  3063.                 SetBackgroundColor(SaveBackground);
  3064.                 NewPicWidth := SavePicWidth;
  3065.                 NewPicHeight := SavePicHeight;
  3066.                 rsMethod := SaveMethod;
  3067.                 rsCreateNewWindow := SaveCreate;
  3068.                 rsAngle := SaveAngle;
  3069.                 rsHScale := SaveH;
  3070.                 rsVScale := SaveV;
  3071.                 InvertYCoordinates := SaveInvertY;
  3072.                 ScaleArithmetic := SaveScaleArithmetic;
  3073.                 ScaleConvolutions := SaveScaleConvolutions;
  3074.                 CurrentFontID:=SaveCurrentFontID;
  3075.                 CurrentSize:=SaveCurrentSize;
  3076.                 CurrentStyle:=SaveCurrentStyle;
  3077.                 TextJust:=SaveTextJust;
  3078.                 TextBack:=SaveTextBack;
  3079. end;
  3080.     end;
  3081.  
  3082.  
  3083.     procedure DoPrint;
  3084.     begin
  3085.         FindWhatToPrint;
  3086.         if WhatToPrint <> NothingToPrint then
  3087.             Print(false)
  3088.         else
  3089.             MacroError('NothingToPrint');
  3090.     end;
  3091.  
  3092.  
  3093.     procedure SetCounter; {(n:integer)}
  3094.         var
  3095.             N, i: LongInt;
  3096.     begin
  3097.         GetLeftParen;
  3098.         N := GetInteger;
  3099.         GetRightParen;
  3100.         if (N < 0) or (N > MaxMeasurements) then
  3101.             MacroError('Argument out of range');
  3102.         if Token <> DoneT then begin
  3103.                 if N = 0 then
  3104.                     ResetCounter;
  3105.                 for i := mCount + 1 to N do
  3106.                     ClearResults(i);
  3107.                 mCount := N;
  3108.                 UpdateList;
  3109.                 ShowInfo;
  3110.             end;
  3111.     end;
  3112.  
  3113.  
  3114.     procedure OutputText;
  3115.         var
  3116.             NewLine: boolean;
  3117.             str: str255;
  3118.             i: integer;
  3119.             SaveCommand: CommandType;
  3120.     begin
  3121.         NewLine := MacroCommand <> WriteC;
  3122.         SaveCommand := MacroCommand;
  3123.         GetArguments(str);
  3124.         if token <> DoneT then begin
  3125.                 if SaveCommand = ShowMsgC then begin
  3126.                         for i := 1 to length(str) do
  3127.                             if str[i] = '\' then
  3128.                                 str[i] := cr;
  3129.                         InfoMessage := str;
  3130.                         ShowInfo;
  3131.                     end
  3132.                 else begin
  3133.                         if CurrentWindow = TextKind then begin
  3134.                             InsertText(str, NewLine);
  3135.                             if not macro then MacroError('32K text limit exceeded')
  3136.                         end else
  3137.                             DoDrawText(str, NewLine);
  3138.                     end;
  3139.             end;
  3140.     end;
  3141.  
  3142.  
  3143.     procedure SetErosionDilationCount; {(n:integer)}
  3144.         var
  3145.             n: LongInt;
  3146.     begin
  3147.         GetLeftParen;
  3148.         n := GetInteger;
  3149.         GetRightParen;
  3150.         if (n < 1) or (n > 8) then
  3151.             MacroError('Argument out of range');
  3152.         if Token <> DoneT then begin
  3153.                 BinaryCount := n;
  3154.                 BinaryThreshold := BinaryCount * 255;
  3155.             end;
  3156.     end;
  3157.  
  3158.  
  3159.     procedure SetSliceSpacing; {(n:real)}
  3160.         var
  3161.             n: extended; {pixels}
  3162.     begin
  3163.         GetLeftParen;
  3164.         n := GetExpression;
  3165.         GetRightParen;
  3166.         if (n <= 0.0) or (n > 100.0) then
  3167.             MacroError('Argument out of range');
  3168.         if info^.StackInfo = nil then
  3169.             MacroError('No stack');
  3170.         if Token <> DoneT then
  3171.             info^.StackInfo^.SliceSpacing := n;
  3172.     end;
  3173.  
  3174.  
  3175.     procedure GetOrPutLineOrColumn;  {(x,y,count:integer:integer)}
  3176.         var
  3177.             x, y, count, i: integer;
  3178.             MaskRect: rect;
  3179.             aLine2: LineType;
  3180.             SaveCommand: CommandType;
  3181.     begin
  3182.         SaveCommand := MacroCommand;
  3183.         GetLeftParen;
  3184.         x := GetInteger;
  3185.         GetComma;
  3186.         y := GetInteger;
  3187.         GetComma;
  3188.         count := GetInteger;
  3189.         GetRightParen;
  3190.         if (Token <> DoneT) and (count <= MaxLine) then
  3191.             with MacrosP^ do begin
  3192.                     KillRoi;
  3193.                     case SaveCommand of
  3194.                         GetRowC: 
  3195.                             GetLine(x, y, count, aLine);
  3196.                         PutRowC:  begin
  3197.                                 PutLine(x, y, count, aLine);
  3198.                                 SetRect(MaskRect, x, y, x + count, y + 1);
  3199.                                 UpdateScreen(MaskRect);
  3200.                                 info^.changes := true;
  3201.                             end;
  3202.                         GetColumnC: 
  3203.                             GetColumn(x, y, count, aLine);
  3204.                         PutColumnC:  begin
  3205.                                 PutColumn(x, y, count, aLine);
  3206.                                 SetRect(MaskRect, x, y, x + 1, y + count);
  3207.                                 UpdateScreen(MaskRect);
  3208.                                 info^.changes := true;
  3209.                             end;
  3210.                     end; {case}
  3211.                 end;
  3212.     end;
  3213.  
  3214.  
  3215.     procedure CheckVersion; {(RequiredVersion:real)}
  3216.         var
  3217.             RequiredVersion: extended;
  3218.             str: str255;
  3219.     begin
  3220.         GetLeftParen;
  3221.         RequiredVersion := GetExpression;
  3222.         GetRightParen;
  3223.         if (Token <> DoneT) then
  3224.             if round(RequiredVersion * 100.0) > version then begin
  3225.                     RealToString(RequiredVersion, 1, 2, str);
  3226.                     PutError(concat('This macro requires version ', str, ' or later of NIH Image.'));
  3227.                     Token := DoneT;
  3228.                 end;
  3229.     end;
  3230.  
  3231.  
  3232.     procedure SetOptions; {(Options:string)}
  3233.         var
  3234.             options: str255;
  3235.             mtype: MeasurementTypes;
  3236.             i, LastOption: integer;
  3237.             SaveMeasurements: SetOfMeasurements;
  3238.     begin
  3239.         GetLeftParen;
  3240.         Options := GetString;
  3241.         GetRightParen;
  3242.         if (Token <> DoneT) then begin
  3243.                 SaveMeasurements := measurements;
  3244.                 MakeLowerCase(options);
  3245.                 Measurements := [];
  3246.                 if pos('area', options) <> 0 then
  3247.                     Measurements := Measurements + [AreaM];
  3248.                 if pos('mean', options) <> 0 then
  3249.                     Measurements := Measurements + [MeanM];
  3250.                 if pos('st', options) <> 0 then
  3251.                     Measurements := Measurements + [StdDevM];
  3252.                 if pos('center', options) <> 0 then
  3253.                     Measurements := Measurements + [xyLocM];
  3254.                 if pos('mode', options) <> 0 then
  3255.                     Measurements := Measurements + [ModeM];
  3256.                 if (pos('per', options) <> 0) or (pos('length', options) <> 0) then
  3257.                     Measurements := Measurements + [LengthM];
  3258.                 if pos('major', options) <> 0 then
  3259.                     Measurements := Measurements + [MajorAxisM];
  3260.                 if pos('minor', options) <> 0 then
  3261.                     Measurements := Measurements + [MinorAxisM];
  3262.                 if pos('angle', options) <> 0 then
  3263.                     Measurements := Measurements + [AngleM];
  3264.                 if pos('int', options) <> 0 then
  3265.                     Measurements := Measurements + [IntDenM];
  3266.                 if pos('max', options) <> 0 then
  3267.                     Measurements := Measurements + [MinMaxM];
  3268.                 if pos('1', options) <> 0 then
  3269.                     Measurements := Measurements + [User1M];
  3270.                 if pos('2', options) <> 0 then
  3271.                     Measurements := Measurements + [User2M];
  3272.                 UpdateFitEllipse;
  3273.                 if Measurements <> SaveMeasurements then
  3274.                     UpdateList;
  3275.             end;
  3276.     end;
  3277.  
  3278.  
  3279.     procedure SetLabel;
  3280.         var
  3281.             SaveCommand: CommandType;
  3282.             str, SaveLabel: str255;
  3283.     begin
  3284.         SaveCommand := MacroCommand;
  3285.         GetArguments(str);
  3286.         TruncateString(str, maxLabelLength);
  3287.         case SaveCommand of
  3288.             SetMajorC:  begin
  3289.                     SaveLabel := MajorLabel;
  3290.                     MajorLabel := str;
  3291.                     Measurements := Measurements + [MajorAxisM];
  3292.                 end;
  3293.             SetMinorC:  begin
  3294.                     SaveLabel := MinorLabel;
  3295.                     MinorLabel := str;
  3296.                     Measurements := Measurements + [MinorAxisM];
  3297.                 end;
  3298.             SetUser1C:  begin
  3299.                     SaveLabel := User1Label;
  3300.                     User1Label := str;
  3301.                     Measurements := Measurements + [User1M];
  3302.                 end;
  3303.             SetUser2C:  begin
  3304.                     SaveLabel := User2Label;
  3305.                     User2Label := str;
  3306.                     Measurements := Measurements + [User2M];
  3307.                 end;
  3308.         end; {case}
  3309.         ShowInfo;
  3310.         if str <> SaveLabel then
  3311.             UpdateList;
  3312.     end;
  3313.  
  3314.  
  3315.     procedure DoUpdateLUT;
  3316.     begin
  3317.         with info^ do begin
  3318.             SetupPseudocolor;
  3319.             LutMode := PseudoColor;
  3320.             IdentityFunction := false;
  3321.             if isGrayScaleLUT then
  3322.                 info^.LutMode := CustomGrayScale;
  3323.             UpdateLut;
  3324.             UpdateMap;
  3325.         end;
  3326.     end;
  3327.  
  3328.  
  3329.     procedure SubtractBackground; {(Options:string; BallRadius:integer)}
  3330.         var
  3331.             options: str255;
  3332.             radius, item: integer;
  3333.     begin
  3334.         GetLeftParen;
  3335.         Options := GetString;
  3336.         GetComma;
  3337.         radius := GetInteger;
  3338.         GetRightParen;
  3339.         if (Token <> DoneT) then begin
  3340.                 MakeLowerCase(options);
  3341.                 FasterBackgroundSubtraction := pos('faster', options) <> 0;
  3342.                 item := Sub2DItem;
  3343.                 if pos('hor', options) <> 0 then
  3344.                     item := HorizontalItem;
  3345.                 if pos('ver', options) <> 0 then
  3346.                     item := VerticalItem;
  3347.                 if pos('roll', options) <> 0 then
  3348.                     item := Sub2DItem;
  3349.                 if pos('remove', options) <> 0 then
  3350.                     item := RemoveStreaksItem;
  3351.             end;
  3352.         BallRadius := Radius;
  3353.         if Radius < 1 then
  3354.             BallRadius := 1;
  3355.         if Radius > 319 then
  3356.             BallRadius := 319;
  3357.         DoBackgroundMenuEvent(Item);
  3358.     end;
  3359.  
  3360.  
  3361.     procedure SetExportMode;
  3362.         var
  3363.             mode: str255;
  3364.     begin
  3365.         mode := GetStringArg;
  3366.         if Token <> DoneT then begin
  3367.                 MakeLowerCase(mode);
  3368.                 ExportAsWhat := AsRaw;
  3369.                 if pos('mcid', mode) <> 0 then
  3370.                     ExportAsWhat := asMCID;
  3371.                 if pos('text', mode) <> 0 then
  3372.                     ExportAsWhat := asText;
  3373.                 if pos('lut', mode) <> 0 then
  3374.                     ExportAsWhat := asLUT;
  3375.                 if pos('meas', mode) <> 0 then
  3376.                     ExportAsWhat := asMeasurements;
  3377.                 if pos('plot', mode) <> 0 then
  3378.                     ExportAsWhat := asPlotValues;
  3379.                 if pos('hist', mode) <> 0 then
  3380.                     ExportAsWhat := asHistogramValues;
  3381.                 if pos('xy', mode) <> 0 then
  3382.                     ExportAsWhat := asCoordinates;
  3383.             end;
  3384.     end;
  3385.  
  3386.  
  3387.     procedure SetSaveAsMode;
  3388.         var
  3389.             mode: str255;
  3390.     begin
  3391.         mode := GetStringArg;
  3392.         if Token <> DoneT then begin
  3393.                 MakeLowerCase(mode);
  3394.                 SaveAsWhat := asTiff;
  3395.                 if pos('tiff', mode) <> 0 then
  3396.                     SaveAsWhat := asTiff;
  3397.                 if pos('pict', mode) <> 0 then
  3398.                     SaveAsWhat := asPict;
  3399.                 if pos('quick', mode) <> 0 then
  3400.                     SaveAsWhat := asQuickTime;
  3401.                 if pos('pics', mode) <> 0 then
  3402.                     SaveAsWhat := asPICS;
  3403.                 if pos('lut', mode) <> 0 then
  3404.                     SaveAsWhat := AsPalette;
  3405.                 if pos('outline', mode) <> 0 then
  3406.                     SaveAsWhat := AsOutline;
  3407.                 if pos('rgb', mode) <> 0 then with info^ do begin
  3408.                     if StackInfo = nil then begin
  3409.                         MacroError('Stack required');
  3410.                         exit(SetSaveAsMode);
  3411.                     end;
  3412.                     if StackInfo^.nSlices <> 3 then begin
  3413.                         MacroError('Stack must have 3 slices');
  3414.                         exit(SetSaveAsMode);
  3415.                     end;
  3416.                     StackInfo^.StackType := rgbStack;
  3417.                     UpdateTitleBar;
  3418.                 end;
  3419.             end;
  3420.     end;
  3421.  
  3422.  
  3423.     procedure MoveCurrentWindow;{(x,y:integer)}
  3424.         var
  3425.             x, y: integer;
  3426.             ignore: integer;
  3427.             fwptr: WindowPtr;
  3428.             kind: integer;
  3429.     begin
  3430.         GetLeftParen;
  3431.         x := GetInteger;
  3432.         GetComma;
  3433.         y := GetInteger;
  3434.         GetRightParen;
  3435.         fwptr := FrontWindow;
  3436.         if fwptr <> nil then begin
  3437.                 kind := WindowPeek(fwptr)^.WindowKind;
  3438.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  3439.                     MoveWindow(fwptr, x, y, true);
  3440.             end;
  3441.     end;
  3442.  
  3443.  
  3444.     procedure DoUserCode; {str:str255; Param1,Param2,Param3:real;}
  3445.   {Contributed by Mark Vivino}
  3446.         var
  3447.             WhichCode: integer;
  3448.             Param1, Param2, Param3: extended;
  3449.             str: str255;
  3450.             NewVersion: boolean;
  3451.     begin
  3452.         GetLeftParen;
  3453.         GetToken;
  3454.         NewVersion := (token = StringLiteral) or (token = StringVariable);
  3455.         PutTokenBack;
  3456.         WhichCode := 0;
  3457.         str := '';
  3458.         if NewVersion then
  3459.             str := GetString
  3460.         else
  3461.             WhichCode := GetInteger;
  3462.         GetComma;
  3463.         Param1 := GetExpression;
  3464.         GetComma;
  3465.         Param2 := GetExpression;
  3466.         GetComma;
  3467.         Param3 := GetExpression;
  3468.         GetRightParen;
  3469.         if Token <> DoneT then begin
  3470.                 if NewVersion then
  3471.                     UserMacroCode(str, Param1, Param2, Param3)
  3472.                 else begin
  3473.                         if (WhichCode < 1) or (WhichCode > 10) then
  3474.                             MacroError('Range error . Allowable range is 1 to 10.');
  3475.                         OldUserMacroCode(WhichCode, Param1, Param2, Param3);
  3476.                     end;
  3477.             end;
  3478.     end;
  3479.  
  3480.  
  3481.     procedure CloseSerialPorts;
  3482.         var
  3483.             err: OSErr;
  3484.     begin
  3485.         if SerialBufferP <> nil then begin
  3486.                 err := CloseDriver(SerialOut);
  3487.                 err := CloseDriver(SerialIn);
  3488.                 DisposePtr(SerialBufferP);
  3489.             end;
  3490.     end;
  3491.  
  3492.  
  3493.     procedure OpenSerial;
  3494.         const
  3495.             SerialBufferSize = 1024;
  3496.         var
  3497.             err: OSErr;
  3498.             baud, data, stop, parity, i: integer;
  3499.             config: integer;
  3500.             flags: SerShk;
  3501.             str: str255;
  3502.     begin
  3503.         CloseSerialPorts;
  3504.         baud := baud9600;
  3505.         data := data8;
  3506.         stop := stop10;
  3507.         parity := noParity;
  3508.         str := GetStringArg;
  3509.         if token = DoneT then
  3510.             exit(OpenSerial);
  3511.         MakeLowerCase(str);
  3512.         if pos('300', str) <> 0 then
  3513.             baud := baud300;
  3514.         if pos('1200', str) <> 0 then
  3515.             baud := baud1200;
  3516.         if pos('2400', str) <> 0 then
  3517.             baud := baud2400;
  3518.         if pos('19200', str) <> 0 then
  3519.             baud := baud19200;
  3520.         if pos('two', str) <> 0 then
  3521.             stop := stop20;
  3522.         if pos('seven', str) <> 0 then
  3523.             data := data7;
  3524.         i:=pos('even', str);
  3525.         if (i <> 0) and (str[i-1]<>'s') then
  3526.             parity := evenParity;
  3527.         if pos('odd', str) <> 0 then
  3528.             parity := oddParity;
  3529.         if (OpenDriver('.AOut', SerialOut) <> NoErr) or (OpenDriver('.AIn', SerialIn) <> NoErr) then begin
  3530.                 MacroError('Error opening modem port');
  3531.                 exit(OpenSerial);
  3532.             end;
  3533.         SerialBufferP := NewPtr(SerialBufferSize);
  3534.         if SerialBufferP = nil then begin
  3535.                 MacroError('Out of Memory');
  3536.                 exit(OpenSerial);
  3537.             end;
  3538.         with flags do begin
  3539.                 fXOn := ord(false); {Disable xon/xoff output flow control}
  3540.                 fCTS := ord(false); {Disable CTS (output) flow control}
  3541.                 xOn := chr(17);
  3542.                 xOff := chr(19);
  3543.                 errs := 0;
  3544.                 evts := 0;
  3545.                 fInX := ord(true);  {Enable xon/xoff input flow control}
  3546.                 fDTR := ord(true); {Enable DTR (input) flow control}
  3547.             end;
  3548.         Config := baud + data + stop + parity;
  3549.         Err := SerHShake(SerialOut, flags);
  3550.         Err := SerSetBuf(SerialIn, SerialBufferP, SerialBufferSize);
  3551.         Err := SerReset(SerialOut, Config);
  3552.     end;
  3553.  
  3554.  
  3555.     procedure PutSerial;
  3556.         var
  3557.             i: integer;
  3558.             Size: LongInt;
  3559.             OutputBuffer: packed array[1..256] of char;
  3560.             str: str255;
  3561.             err: OSErr;
  3562.     begin
  3563.         GetArguments(str);
  3564.         if token = DoneT then
  3565.             exit(PutSerial);
  3566.         if SerialBufferP = nil then begin
  3567.                 MacroError('Serial port not open');
  3568.                 exit(PutSerial);
  3569.             end;
  3570.         Size := 0;
  3571.         for i := 1 to length(str) do begin
  3572.                 size := size + 1;
  3573.                 OutputBuffer[size] := str[i];
  3574.             end;
  3575.         if size > 0 then
  3576.             err := fswrite(SerialOut, size, @OutputBuffer);
  3577.     end;
  3578.  
  3579.  
  3580.     procedure DoSetCursor; {str: string}
  3581.         var
  3582.             str: str255;
  3583.     begin
  3584.         str := GetStringArg;
  3585.         if Token <> DoneT then begin
  3586.                 MakeLowerCase(str);
  3587.                 if pos('watch', str) <> 0 then
  3588.                     SetCursor(watch);
  3589.                 if pos('cross', str) <> 0 then
  3590.                     SetCursor(ToolCursor[SelectionTool]);
  3591.                 if pos('arrow', str) <> 0 then
  3592.                     InitCursor;
  3593.                 if pos('finger', str) <> 0 then
  3594.                     SetCursor(FingerCursor);
  3595.             end;
  3596.     end;
  3597.  
  3598.  
  3599.     procedure SetVideoOptions; {options: string[, gain:integer, offset:integer]}
  3600.         var
  3601.             options: str255;
  3602.             NewSyncMode: SyncModeType;
  3603.       gain, offset: integer;
  3604.  
  3605.         procedure SetOption (id: integer; var option: boolean; enable: boolean);
  3606.     {Updates the modeless Video Control dialog box.}
  3607.         begin
  3608.             if option <> enable then
  3609.                 DoVideoControl(id)
  3610.         end;
  3611.  
  3612.     begin
  3613.         GetLeftParen;
  3614.         options := GetString;
  3615.         GetToken;
  3616.         if token = comma then begin
  3617.             gain := GetInteger;
  3618.             GetComma;
  3619.             offset := GetInteger
  3620.         end
  3621.         else begin
  3622.             PutTokenBack;
  3623.             gain := 255 - (DacHigh - DacLow);
  3624.             offset := DacLow;
  3625.         end;
  3626.         GetRightParen;
  3627.         if Token <> DoneT then begin
  3628.                 MakeLowerCase(options);
  3629.                 SetOption(InvertID, InvertVideo, pos('invert', options) <> 0);
  3630.                 SetOption(HighlightID, HighlightSaturatedPixels, pos('high', options) <> 0);
  3631.                 SetOption(TriggerID, ExternalTrigger, pos('trig', options) <> 0);
  3632.                 if pos('sep', options) <> 0 then
  3633.                     NewSyncMode := SeparateSync
  3634.                 else
  3635.                     NewSyncMode := NormalSync;
  3636.                 if NewSyncMode <> SyncMode then
  3637.                     DoVideoControl(SyncID);
  3638.                 SetOffset(offset, gain);
  3639.                 SetGain(offset, gain);
  3640.                 if VideoControl <> nil then begin
  3641.                     gain := 255 - (DacHigh - DacLow);
  3642.                     ShowOffsetAndGain(DacLow, gain);
  3643.                 end;
  3644.                 OscillatingMovies := pos('osc', options) <> 0;
  3645.                 BlindMovieCapture := pos('blind', options) <>0;
  3646.                 if (FrameGrabber = ScionLG3) or (FrameGrabber=ScionAG5) or (FrameGrabber=ScionVG5f) then begin
  3647.                         DacLowReg^ := DacLow;
  3648.                         DacHighReg^ := DacHigh;
  3649.                     end;
  3650.             end;
  3651.     end;
  3652.  
  3653.  
  3654.     procedure SetChannel; {(channel:integer)}
  3655.         var
  3656.             channel: integer;
  3657.     begin
  3658.         GetLeftParen;
  3659.         channel := GetInteger;
  3660.         GetRightParen;
  3661.         if (channel < 1) or (channel > 4) then
  3662.             MacroError('Bad channel number')
  3663.         else
  3664.             DoVideoControl(FirstChannelID + channel - 1);
  3665.     end;
  3666.  
  3667.  
  3668.     procedure DoAcquire;
  3669.         var
  3670.             fname: str255;
  3671.     begin
  3672.         fname := GetStringArg;
  3673.         LoadAcqPlugIn(fname);
  3674.     end;
  3675.  
  3676.  
  3677.     procedure CallExportPlugin;
  3678.         var
  3679.             fname: str255;
  3680.     begin
  3681.         fname := GetStringArg;
  3682.         LoadExportPlugIn(fname);
  3683.     end;
  3684.  
  3685.  
  3686.     procedure CallFilterPlugin;
  3687.         var
  3688.             fname: str255;
  3689.     begin
  3690.         fname := GetStringArg;
  3691.         LoadFilterPlugIn(fname);
  3692.     end;
  3693.  
  3694.  
  3695.     procedure DoPhotoMode;
  3696.         var
  3697.             erase: boolean;
  3698.     begin
  3699.         erase := GetBooleanArg;
  3700.         if Token <> DoneT then begin
  3701.                 if erase then begin
  3702.                         EraseScreen;
  3703.                         UpdatePicWindow;
  3704.                         InPhotoMode := true;
  3705.                     end
  3706.                 else if InPhotoMode then
  3707.                         RestoreScreen;
  3708.             end;
  3709.     end;
  3710.  
  3711.  
  3712.     procedure RGBToIndexed; {options: string}
  3713.         var
  3714.             options: str255;
  3715.     begin
  3716.         options := GetStringArg;
  3717.         if Token <> DoneT then begin
  3718.                 MakeLowerCase(options);
  3719.                 RGBLut := CustomLUT;
  3720.                 DitherColor := false;
  3721.                 if pos('exist', options) <> 0 then
  3722.                     RGBLut := ExistingLUT;
  3723.                 if pos('system', options) <> 0 then
  3724.                     RGBLut := SystemLUT;
  3725.                 if pos('dither', options) <> 0 then
  3726.                     DitherColor := true;
  3727.                 ConvertRGBToEightBitColor(false);
  3728.             end;
  3729.     end;
  3730.  
  3731.  
  3732.  procedure DoAverageFrames; {[(Options:string; nFrames:integer)]}
  3733.   var
  3734.    options: str255;
  3735.    nFrames: LongInt;
  3736.    HasArguments,ShowDialog,okay: boolean;
  3737.  begin
  3738.   GetToken;
  3739.   HasArguments := token = LeftParen;
  3740.   PutTokenBack;
  3741.   ShowDialog:=false;
  3742.   if HasArguments then begin
  3743.     GetLeftParen;
  3744.     Options := GetString;
  3745.     GetComma;
  3746.     nFrames := GetInteger;
  3747.     ShowDialog:= nFrames <= 0;
  3748.     if not ShowDialog then
  3749.         FramesToAverage := nFrames;
  3750.     GetRightParen;
  3751.     if (Token <> DoneT) then begin
  3752.       MakeLowerCase(options);
  3753.       VideoRateAveraging := false;
  3754.       SumFrames := false;
  3755.       IntegrateOnChip := false;
  3756.       if (pos('int', options) <> 0) or (pos('sum', options) <> 0) then
  3757.        sumFrames := true;
  3758.       if pos('video', options) <> 0 then
  3759.        VideoRateAveraging := true;
  3760.       if (pos('camera', options) <> 0) or (pos('chip', options) <> 0) then begin
  3761.        if  (FrameGrabber<>ScionLG3) and (FrameGrabber<>ScionAG5) and (FrameGrabber<>ScionVG5f) then begin
  3762.          MacroError('On-chip integration requires a Scion frame grabber.');
  3763.          exit(DoAverageFrames)
  3764.        end;
  3765.        VideoRateAveraging := false;
  3766.        SumFrames := false;
  3767.        IntegrateOnChip := true;
  3768.        end;
  3769.      end;
  3770.    end; {has arguments}
  3771.   if token <> DoneT then begin
  3772.    if ShowDialog
  3773.     then okay:=DoAveragingOptions
  3774.     else okay:=true;
  3775.    if okay then AverageFrames;
  3776.   end;
  3777.  end;
  3778.  
  3779.  
  3780.     procedure DoSelectWindow;{('str')}
  3781.         var
  3782.             str, wTitle: str255;
  3783.             WPeek, NextWPeek: WindowPeek;
  3784.             id: integer;
  3785.             TempInfo: InfoPtr;
  3786.     begin
  3787.         GetArguments(str);
  3788.         MakeLowerCase(str);
  3789.         if Token <> DoneT then begin
  3790.                 wPeek := WindowPeek(FrontWindow);
  3791.                 while wPeek <> nil do begin
  3792.                         NextWPeek := wPeek^.NextWindow;
  3793.                         if wPeek^.WindowKind = PicKind then begin
  3794.                                 TempInfo := InfoPtr(wPeek^.RefCon);
  3795.                                 wTitle := TempInfo^.title;
  3796.                             end
  3797.                         else
  3798.                             wTitle := wPeek^.TitleHandle^^;
  3799.                         MakeLowerCase(wTitle);
  3800.                         if str = wTitle then begin
  3801.                                 if wPeek^.WindowKind = PicKind then begin
  3802.                                         info := InfoPtr(wPeek^.RefCon);
  3803.                                         with info^ do
  3804.                                             if (PicNum >= 1) and (PicNum <= nPics) then
  3805.                                                 SelectImage(PicNum);
  3806.                                     end
  3807.                                 else
  3808.                                     SelectWindow(WindowPtr(wPeek));
  3809.                                 leave;
  3810.                             end;
  3811.                         wpeek := NextWPeek;
  3812.                     end;
  3813.                 if wPeek = nil then
  3814.                     MacroError('Window not found');
  3815.             end;
  3816.     end;
  3817.  
  3818.  
  3819.     procedure GetThreshold;  {(lower,upper)}
  3820.         var
  3821.             loc1, loc2: integer;
  3822.     begin
  3823.         GetLeftParen;
  3824.         loc1 := GetVar;
  3825.         GetComma;
  3826.         loc2 := GetVar;
  3827.         GetRightParen;
  3828.         if Token <> DoneT then
  3829.             with MacrosP^ do
  3830.                 with info^ do begin
  3831.                         if Thresholding then begin
  3832.                                 stack[loc1].value := ColorStart;
  3833.                                 stack[loc2].value := 255;
  3834.                             end
  3835.                         else if DensitySlicing then begin
  3836.                                 stack[loc1].value := SliceStart;
  3837.                                 stack[loc2].value := SliceEnd;
  3838.                             end
  3839.                         else begin
  3840.                                 stack[loc1].value := 0;
  3841.                                 stack[loc2].value := 0;
  3842.                             end;
  3843.                     end;
  3844.     end;
  3845.  
  3846.  
  3847.     procedure SortPalette;
  3848.         type
  3849.             MyHSVColor = record
  3850.                     lHue, lSaturation, lValue: LongInt;
  3851.                 end;
  3852.             HSVRec = record
  3853.                     index: integer;
  3854.                     hsv: MyHSVColor;
  3855.                 end;
  3856.             HSVArrayType = array[0..255] of HSVRec;
  3857.         var
  3858.             TempTable: MyCSpecArray;
  3859.             i: integer;
  3860.             HSVArray: HSVArrayType;
  3861.             h, s, v: LongInt;
  3862.             fHue, fSaturation, fValue: fixed;
  3863.             TempHSV: HSVColor;
  3864.             table: LookupTable;
  3865.  
  3866.         procedure SortByHue;
  3867.     {Selection sorts from "Algorithms" by Robert Sedgewick.}
  3868.             var
  3869.                 i, j, min: integer;
  3870.                 t: HSVRec;
  3871.         begin
  3872.             for i := 1 to 254 do begin
  3873.                     min := i;
  3874.                     for j := i + 1 to 254 do
  3875.                         if HSVArray[j].hsv.lHue < HSVArray[min].hsv.lHue then
  3876.                             min := j;
  3877.                     t := HSVArray[min];
  3878.                     HSVArray[min] := HSVArray[i];
  3879.                     HSVArray[i] := t;
  3880.                 end;
  3881.         end;
  3882.  
  3883.     begin
  3884.         ShowWatch;
  3885.         DisableDensitySlice;
  3886.         with info^ do begin
  3887.                 for i := 1 to 254 do begin
  3888.                         HSVArray[i].index := i;
  3889.                         rgb2hsv(cTable[i].rgb, TempHSV);
  3890.                         with TempHSV do begin
  3891.                                 fHue := SmallFract2Fix(hue);
  3892.                                 fSaturation := SmallFract2Fix(saturation);
  3893.                                 fValue := SmallFract2Fix(value);
  3894.                             end;
  3895.                         with HSVArray[i].hsv do begin
  3896.                                 lHue := ord4(band(fHue, $ffff));
  3897.                                 lSaturation := ord4(band(fSaturation, $ffff));
  3898.                                 lValue := ord4(band(fValue, $ffff));
  3899.                             end;
  3900.                     end;
  3901.                 SortByHue;
  3902.                 for i := 1 to 254 do
  3903.                     TempTable[i].rgb := cTable[HSVArray[i].index].rgb;
  3904.                 cTable := TempTable;
  3905.                 LoadLUT(cTable);
  3906.                 if info <> NoInfo then begin
  3907.                         table[0] := 0;
  3908.                         table[255] := 255;
  3909.                         for i := 1 to 254 do
  3910.                             table[HSVArray[i].index] := i;
  3911.                         ApplyTable(table);
  3912.                     end;
  3913.                 WhatToUndo := NothingToUndo;
  3914.                 SetupPseudocolor;
  3915.                 ColorTable := CustomTable;
  3916.             end; {with}
  3917.     end;
  3918.  
  3919.  
  3920.     procedure DoProject;
  3921.     begin
  3922.         if info^.StackInfo = nil then begin
  3923.             MacroError('Stack required');
  3924.             exit(DoProject);
  3925.         end;
  3926.         if not ((ProjectC in RoutinesCalled) or (SetProjectionC in RoutinesCalled)) then begin
  3927.                 if ShowProjectDialogBox then
  3928.                     DoProjection
  3929.                 else
  3930.                     token := DoneT;
  3931.             end
  3932.         else with info^.StackInfo^ do begin
  3933.             if SliceSpacing <= 0.0 then
  3934.                 SliceSpacing := 1.0;
  3935.             if DensitySlicing then
  3936.                 with info^ do begin
  3937.                         TransparencyLower := SliceStart;
  3938.                         TransparencyUpper := SliceEnd;
  3939.                     end;
  3940.             DoProjection;
  3941.         end;
  3942.         RoutinesCalled := RoutinesCalled + [ProjectC];
  3943.     end;
  3944.  
  3945.  
  3946.     procedure DoNewTextWindow; {(name,width,height)}
  3947.         var
  3948.             str: str255;
  3949.             okay, OptionalArguments: boolean;
  3950.             width, height: LongInt;
  3951.     begin
  3952.         GetLeftParen;
  3953.         str := GetString;
  3954.         GetToken;
  3955.         OptionalArguments := token <> RightParen;
  3956.         PutTokenBack;
  3957.         width := 500;
  3958.         height := 400;
  3959.         if OptionalArguments then begin
  3960.                 GetComma;
  3961.                 width := GetInteger;
  3962.                 if width < 8 then
  3963.                     width := 8;
  3964.                 GetComma;
  3965.                 height := GetInteger;
  3966.                 if height < 8 then
  3967.                     height := 8;
  3968.             end;
  3969.         GetRightParen;
  3970.         if Token <> DoneT then
  3971.             okay := MakeNewTextWindow(str, width, height);
  3972.     end;
  3973.  
  3974.  
  3975.     procedure ImageMath; {('op',pic1,pic2,gain,offset,'result')}
  3976.         var
  3977.             op, result: str255;
  3978.             pic1, pic2, DstPidNum: LongInt;
  3979.             gain, offset: extended;
  3980.             roi:rect;
  3981.             DstInfo:InfoPtr;
  3982.             isPidNum:boolean;
  3983.     begin
  3984.         GetLeftParen;
  3985.         op := GetString;
  3986.         GetComma;
  3987.         pic1 := GetInteger;
  3988.         GetComma;
  3989.         pic2 := GetInteger;
  3990.         GetComma;
  3991.         gain := GetExpression;
  3992.         GetComma;
  3993.         offset := GetExpression;
  3994.         GetComma;
  3995.         GetToken;
  3996.         isPidNum:=token=variable;
  3997.         PutTokenBack;
  3998.         if isPidNum
  3999.             then DstPidNum:=GetInteger
  4000.             else result := GetString;
  4001.         GetRightParen;
  4002.         if token <> DoneT then begin
  4003.                 MakeLowerCase(op);
  4004.                 RealImageMath:=false;
  4005.                 if pos('calibrate', op) <> 0 then
  4006.                     RealImageMath := true;
  4007.                 if pos('real', op) <> 0 then
  4008.                     RealImageMath := true;
  4009.                 if pos('add', op) <> 0 then
  4010.                     CurrentMathOp := AddMath;
  4011.                 if pos('sub', op) <> 0 then
  4012.                     CurrentMathOp := SubMath;
  4013.                 if pos('mul', op) <> 0 then
  4014.                     CurrentMathOp := MulMath;
  4015.                 if (pos('cmul', op) <> 0) or (pos('conjugate', op) <> 0) then begin
  4016.                     CurrentMathOp := cMulMath;
  4017.                     RealImageMath := true;
  4018.                 end;
  4019.                 if pos('div', op) <> 0 then
  4020.                     CurrentMathOp := DivMath;
  4021.                 if pos('and', op) <> 0 then
  4022.                     CurrentMathOp := AndMath;
  4023.                 if pos('or', op) <> 0 then
  4024.                     CurrentMathOp := OrMath;
  4025.                 if pos('xor', op) <> 0 then
  4026.                     CurrentMathOp := XorMath;
  4027.                 if pos('max', op) <> 0 then
  4028.                     CurrentMathOp := MaxMath;
  4029.                 if pos('min', op) <> 0 then
  4030.                     CurrentMathOp := MinMath;
  4031.                 if pos('copy', op) <> 0 then
  4032.                     CurrentMathOp := CopyMath;
  4033.                 MathGain := gain;
  4034.                 MathOffset := offset;
  4035.                 if not GetMathRoi(pic1, pic2, roi) then
  4036.                     exit(ImageMath);
  4037.                 if isPidNum then begin
  4038.                     DstInfo := GetInfoPtr(DstPidNum);
  4039.                     if DstInfo=nil then begin
  4040.                         MacroError('Bad pid number');
  4041.                         exit(ImageMath);
  4042.                     end;
  4043.                     if RealImageMath and (DstInfo^.dataH = nil) then begin
  4044.                         MacroError('Real output image required');
  4045.                         exit(ImageMath);
  4046.                     end;
  4047.                     SelectWindow(DstInfo^.wptr);
  4048.                     Info := DstInfo;
  4049.                     ActivateWindow;
  4050.                     LoadLUT(info^.cTable);
  4051.                     UpdatePicWindow;
  4052.                     KillRoi;
  4053.                 end else begin
  4054.                     with roi do
  4055.                         if RealImageMath then begin
  4056.                             if not NewRealWindow(result, right-left, bottom-top) then
  4057.                                 exit(ImageMath)
  4058.                         end else begin
  4059.                             if not NewPicWindow(result, right-left, bottom-top) then
  4060.                                 exit(ImageMath)
  4061.                         end;
  4062.                     DstInfo := Info;
  4063.                 end;
  4064.                 DoMath(pic1, pic2, DstInfo, roi);
  4065.             end;
  4066.     end;
  4067.  
  4068.  
  4069.     procedure PasteLive;
  4070.     begin
  4071.         with info^ do begin
  4072.                 if not RoiShowing or (RoiType <> RectRoi) then begin
  4073.                         MacroError('No selection');
  4074.                         exit(PasteLive);
  4075.                     end;
  4076.                 if PictureType = FrameGrabberType then begin
  4077.                         MacroError('Can''t paste into Camera window');
  4078.                         exit(PasteLive);
  4079.                     end;
  4080.                 if FrameGrabber = NoFrameGrabber then begin
  4081.                         MacroError('No frame grabber');
  4082.                         exit(PasteLive);
  4083.                     end;
  4084.                 if (RoiRect.right > fgwidth) or (RoiRect.bottom > fgheight) then begin
  4085.                         MacroError('Selection out of range');
  4086.                         exit(PasteLive);
  4087.                     end;
  4088.                 SetupUndo;
  4089.                 WhatToUndo := UndoPaste;
  4090.                 ClipBufInfo^.RoiRect := RoiRect;
  4091.                 OpPending := true;
  4092.                 CurrentOp := PasteOp;
  4093.                 LivePasteMode := true;
  4094.                 WhatsOnClip := LivePic;
  4095.             end;{with}
  4096.     end;
  4097.  
  4098.  
  4099.     procedure GetPlotData;  {(var nValues,PixelsPerValue, Min,Max:real)}
  4100.         var
  4101.             loc1, loc2, loc3, loc4: integer;
  4102.     begin
  4103.         GetLeftParen;
  4104.         loc1 := GetVar;
  4105.         GetComma;
  4106.         loc2 := GetVar;
  4107.         GetComma;
  4108.         loc3 := GetVar;
  4109.         GetComma;
  4110.         loc4 := GetVar;
  4111.         GetRightParen;
  4112.         if Token <> DoneT then
  4113.             with MacrosP^, results do begin
  4114.                     ShowPlot := false;
  4115.                     PlotDensityProfile;
  4116.                     ShowPlot := true;
  4117.                     stack[loc1].value := PlotCount;
  4118.                     stack[loc2].value := PlotAvg;
  4119.                     stack[loc3].value := ActualPlotMin;
  4120.                     stack[loc4].value := ActualPlotMax;
  4121.                 end;
  4122.     end;
  4123.  
  4124.  
  4125.     procedure DoDelete;  {(var dest; index, count:integer)}
  4126.         var
  4127.             StackLoc, index, count: integer;
  4128.             str: str255;
  4129.     begin
  4130.         GetLeftParen;
  4131.         StackLoc := GetStringVar;
  4132.         str := TokenStr;
  4133.         GetComma;
  4134.         index := GetInteger;
  4135.         GetComma;
  4136.         count := GetInteger;
  4137.         GetRightParen;
  4138.         if Token <> DoneT then
  4139.             with MacrosP^.stack[StackLoc] do begin
  4140.                     delete(str, index, count);
  4141.                     if StringH <> nil then
  4142.                         StringH^^ := str;
  4143.                 end;
  4144.     end;
  4145.  
  4146.  
  4147.     procedure DoAutoOutline;  {(x,y:integer)}
  4148.         var
  4149.             x, y: integer;
  4150.             start: point;
  4151.     begin
  4152.         GetLeftParen;
  4153.         x := GetInteger;
  4154.         GetComma;
  4155.         y := GetInteger;
  4156.         GetRightParen;
  4157.         if Token <> DoneT then begin
  4158.                 start.h := x;
  4159.                 start.v := y;
  4160.                 AutoOutline(start);
  4161.             end;
  4162.     end;
  4163.  
  4164.  
  4165.     procedure DoFilter; {(fType:string)}
  4166.         var
  4167.             fType: str255;
  4168.             doMore:boolean;
  4169.             t:FateTable;
  4170.     begin
  4171.         GetLeftParen;
  4172.         fType := GetString;
  4173.         GetRightParen;
  4174.         if token <> DoneT then begin
  4175.                 MakeLowerCase(fType);
  4176.                 doMore:=pos('more', fType) <> 0;
  4177.                 if pos('smooth', fType) <> 0 then begin
  4178.                     if doMore then
  4179.                         Filter(UnweightedAvg, 0, t)
  4180.                     else
  4181.                         Filter(WeightedAvg, 0, t);
  4182.                     exit(DoFilter);
  4183.                 end;
  4184.                 if pos('sharpen', fType) <> 0 then begin
  4185.                     if doMore then
  4186.                         Filter(SharpenMore, 0, t)
  4187.                     else
  4188.                         Filter(fsharpen, 0, t);
  4189.                     exit(DoFilter);
  4190.                 end;
  4191.                 if pos('median', fType) <> 0 then begin
  4192.                     RankFilter := MedianRank;
  4193.                     DoRankFilter;
  4194.                     exit(DoFilter);
  4195.                 end;
  4196.                 if (pos('edges', fType) <> 0) or (pos('sobel', fType)<>0) then begin
  4197.                     Filter(FindEdges, 0, t);
  4198.                     exit(DoFilter);
  4199.                 end;
  4200.                 if pos('dither', fType) <> 0 then begin
  4201.                     Filter(Dither, 0, t);
  4202.                     exit(DoFilter);
  4203.                 end;
  4204.                 if pos('min', fType) <> 0 then begin
  4205.                     RankFilter := MinRank;
  4206.                     DoRankFilter;
  4207.                     exit(DoFilter);
  4208.                 end;
  4209.                 if pos('max', fType) <> 0 then begin
  4210.                     RankFilter := MaxRank;
  4211.                     DoRankFilter;
  4212.                     exit(DoFilter);
  4213.                 end;
  4214.                 MacroError('Undefined filter');
  4215.             end;
  4216.     end;
  4217.  
  4218.  
  4219.     procedure DoShadow; {[(Direction:string)]}
  4220.         var
  4221.             direction: str255;
  4222.             t: FateTable;
  4223.     begin
  4224.         GetToken;
  4225.         if token =LeftParen then begin
  4226.             direction := GetString;
  4227.             MakeLowerCase(direction);
  4228.             GetRightParen;
  4229.         end else begin
  4230.             PutTokenBack;
  4231.             direction:='se';
  4232.         end;
  4233.         if Token <> DoneT then
  4234.         if direction='n' then Filter(ShadowN, 0, t)
  4235.         else if direction='ne' then Filter(ShadowNE, 0, t)
  4236.         else if direction='e'  then Filter(ShadowE, 0, t)
  4237.         else if direction='se' then Filter(ShadowSE, 0, t)
  4238.         else if direction='s'  then Filter(ShadowS, 0, t)
  4239.         else if direction='sw' then Filter(ShadowSW, 0, t)
  4240.         else if direction='w'  then Filter(ShadowW, 0, t)
  4241.         else if direction='nw' then Filter(ShadowNW, 0, t)
  4242.         else MacroError('Invalid direction');
  4243.         end;
  4244.  
  4245.  
  4246.     procedure DoCalibrate; {(fit,unit:string,m1,k1,m2,k2,...)}
  4247.         var
  4248.             sFit, sUnit: str255;
  4249.             Measured, Known:StandardsArray;
  4250.             nPairs, i:integer;
  4251.     begin
  4252.         GetLeftParen;
  4253.         sFit := GetString;
  4254.         if token <> DoneT then with info^ do begin
  4255.                 MakeLowerCase(sFit);
  4256.                 if pos('straight', sFit) <> 0 then fit:=StraightLine
  4257.                 else if pos('rodbard', sFit) <> 0 then fit:=RodbardFit
  4258.                 else if pos('od', sFit) <> 0 then fit:=UncalibratedOD
  4259.                 else if pos('uncal', sFit) <> 0 then fit:=Uncalibrated
  4260.                 else if pos('exp', sFit) <> 0 then fit:=ExpoFit
  4261.                 else if pos('log', sFit) <> 0 then fit:=LogFit
  4262.                 else if pos('pow', sFit) <> 0 then fit:=PowerFit
  4263.                 else if pos('poly2', sFit) <> 0 then fit:=Poly2
  4264.                 else if pos('poly3', sFit) <> 0 then fit:=Poly3
  4265.                 else if pos('poly4', sFit) <> 0 then fit:=Poly4
  4266.                 else if pos('poly5', sFit) <> 0 then fit:=Poly5
  4267.                 else begin
  4268.                     MacroError('Unknown fit');
  4269.                     exit(DoCalibrate);
  4270.                 end;
  4271.                 if (fit=Uncalibrated) or (fit=UncalibratedOD) then begin
  4272.                     GetRightParen;
  4273.                     Calibrate;
  4274.                     exit(DoCalibrate);
  4275.                 end;
  4276.         end;
  4277.         GetComma;
  4278.         sUnit := GetString;
  4279.         GetComma;
  4280.         nPairs:=0;
  4281.         GetToken;
  4282.         while (token<>RightParen) and (token<>DoneT) do begin
  4283.             PutTokenBack;
  4284.             if nPairs<MaxStandards then
  4285.                 nPairs:=nPairs+1;
  4286.             Measured[nPairs]:=GetExpression;
  4287.             GetComma;
  4288.             Known[nPairs]:=GetExpression;
  4289.             GetToken;
  4290.             if token=comma then
  4291.                 GetToken;
  4292.         end;
  4293.         if token <> DoneT then with info^ do begin
  4294.                 if nPairs<2 then begin
  4295.                     MacroError('More arguments expected');
  4296.                     exit(DoCalibrate);
  4297.                 end;
  4298.                 TruncateString(sUnit, maxUM);
  4299.                 UnitOfMeasure:=sUnit;
  4300.                 nStandards:=nPairs;
  4301.                 nKnownValues:=nPairs;
  4302.                 for i:=1 to nStandards do begin
  4303.                     ClearResults(i);
  4304.                     uMean[i]:=Measured[i];
  4305.                     Mean^[i]:=Measured[i];
  4306.                     StandardValues[i]:=Known[i];
  4307.                 end;
  4308.                 mCount := nStandards;
  4309.                 UpdateList;
  4310.                 Calibrate;
  4311.             end;
  4312.     end;
  4313.  
  4314.  
  4315.     procedure DoMakeMovie; {(Options:string; nFrames:integer; delay:extended)}
  4316.         var
  4317.             options: str255;
  4318.             nFrames: integer;
  4319.             delay: extended;
  4320.             ShowDialog: boolean;
  4321.     begin
  4322.             GetLeftParen;
  4323.             Options := GetString;
  4324.             GetComma;
  4325.             nFrames := GetInteger;
  4326.             GetComma;
  4327.             delay := GetExpression;
  4328.             GetRightParen;
  4329.             if (Token <> DoneT) then begin
  4330.                     ShowDialog := pos('dialog', options) <> 0;
  4331.                     if ShowDialog and (length(options) = 6) then begin
  4332.                         MakeMovie(true);
  4333.                         exit(DoMakeMovie);
  4334.                     end;
  4335.                     if nFrames > 0 then
  4336.                         FramesWanted := nFrames;
  4337.                     if delay >= 0.0 then
  4338.                         SecondsPerFrame := delay;
  4339.                     MakeLowerCase(options);
  4340.                     BlindMovieCapture := false;
  4341.                     LG3BufferCapture := false;
  4342.                     TriggerFirstFrameOnly := true;
  4343.                     TimeStamp := false;
  4344.                     UseExistingStack := false;
  4345.                     if pos('blind', options) <> 0 then
  4346.                         BlindMovieCapture := true;
  4347.                     if (pos('buffer', options) <> 0) then
  4348.                         LG3BufferCapture := true;
  4349.                     if (pos('stamp', options) <> 0) then
  4350.                             TimeStamp := true;
  4351.                     if (pos('trigger', options) <> 0) and (pos('first', options) <> 0) then begin
  4352.                         ExternalTrigger := true;
  4353.                         TriggerFirstFrameOnly := true;
  4354.                       end;
  4355.                     if (pos('trigger', options) <> 0) and (pos('each', options) <> 0) then begin
  4356.                         ExternalTrigger := true;
  4357.                         TriggerFirstFrameOnly := false;
  4358.                       end;
  4359.                     if (pos('existing', options) <> 0) then
  4360.                             UseExistingStack := true;
  4361.                     MakeMovie(ShowDialog);
  4362.                 end;
  4363.     end;
  4364.  
  4365.  
  4366.     procedure DoAnalyzeParticles; {[(Options:string)]}
  4367.         var
  4368.             options: str255;
  4369.             hasOptions, okay: boolean;
  4370.     begin
  4371.         GetToken;
  4372.         hasOptions := token = LeftParen;
  4373.         PutTokenBack;
  4374.         if hasOptions then begin
  4375.             GetArguments(options);
  4376.             MakeLowerCase(options);
  4377.             if pos('dialog', options) <> 0 then begin
  4378.                 okay := DoAPDialog;
  4379.                 if okay then
  4380.                     AnalyzeParticles;
  4381.                 exit(DoAnalyzeParticles);
  4382.             end;
  4383.             LabelParticles := false;
  4384.             OutlineParticles := false;
  4385.             IgnoreParticlesTouchingEdge := false;
  4386.             IncludeHoles := false;
  4387.             APReset := false;
  4388.             if pos('label', options) <> 0 then
  4389.                 LabelParticles := true;
  4390.             if pos('outline', options) <> 0 then
  4391.                 OutlineParticles := true;
  4392.             if pos('ignore', options) <> 0 then
  4393.                 IgnoreParticlesTouchingEdge := true;
  4394.             if pos('include', options) <> 0 then
  4395.                 IncludeHoles := true;
  4396.             if pos('reset', options) <> 0 then
  4397.                 APReset := true;
  4398.         end;
  4399.         AnalyzeParticles;
  4400.     end;
  4401.  
  4402.  
  4403.   procedure SetProjection;
  4404.     var
  4405.       v: extended;
  4406.       s: str255;
  4407.   begin
  4408.     GetLeftParen;
  4409.     s := GetString;
  4410.         MakeLowerCase(s);
  4411.     if pos('x-axis', s) <> 0 then
  4412.       AxisOfRotation := XAxis
  4413.     else if pos('y-axis', s) <> 0 then
  4414.       AxisOfRotation := YAxis
  4415.     else if pos('z-axis', s) <> 0 then
  4416.       AxisOfRotation := ZAxis
  4417.     else if pos('nearest', s) <> 0 then
  4418.       ProjectionMethod := NearestPoint
  4419.     else if pos('brightest', s) <> 0 then
  4420.       ProjectionMethod := BrightestPoint
  4421.     else if pos('mean', s) <> 0 then
  4422.       ProjectionMethod := MeanValue
  4423.     else begin
  4424.         GetComma;
  4425.         if pos('save', s) <> 0 then
  4426.           SaveProjections := GetBoolean
  4427.         else if pos('minimize', s) <> 0 then
  4428.           MinProjSize := GetBoolean
  4429.         else begin
  4430.             v := GetExpression;
  4431.             if pos('initial', s) <> 0 then
  4432.               InitAngle := round(v)
  4433.             else if pos('total', s) <> 0 then
  4434.               TotalAngle := round(v)
  4435.             else if pos('increment', s) <> 0 then
  4436.               AngleInc := round(v)
  4437.             else if pos('opacity', s) <> 0 then
  4438.               Opacity := round(v)
  4439.             else if pos('surface', s) <> 0 then
  4440.               DepthCueSurf := 100 - round(v)
  4441.             else if pos('interior', s) <> 0 then
  4442.               DepthCueInt := 100 - round(v)
  4443.             else
  4444.               MacroError('String not recognized:');
  4445.           end;
  4446.       end;
  4447.     GetRightParen;
  4448.         RoutinesCalled := RoutinesCalled + [SetProjectionC];
  4449.   end;
  4450.   
  4451.   
  4452.     procedure DoGetHistogram;
  4453.         var
  4454.             Left, Top, Width, Height: integer;
  4455.             SaveRoiRect: rect;
  4456.     begin
  4457.         GetLeftParen;
  4458.         left := GetInteger;
  4459.         GetComma;
  4460.         top := GetInteger;
  4461.         GetComma;
  4462.         width := GetInteger;
  4463.         if width < 1 then
  4464.             width := 1;
  4465.         GetComma;
  4466.         height := GetInteger;
  4467.         if height < 1 then
  4468.             height := 1;
  4469.         GetRightParen;
  4470.         if token <> DoneT then
  4471.             with Info^ do begin
  4472.                     SaveRoiRect := RoiRect;
  4473.                     SetRect(RoiRect, left, top, left + width, top + height);
  4474.                     GetRectHistogram;
  4475.                     RoiRect := SaveRoiRect;
  4476.                 end;
  4477.     end;
  4478.  
  4479.  
  4480.     procedure doFFTMacro; {(Options:string)}
  4481.         var
  4482.             options: str255;
  4483.     begin
  4484.         GetLeftParen;
  4485.         Options := GetString;
  4486.         GetRightParen;
  4487.         if (Token <> DoneT) then begin
  4488.                 MakeLowerCase(options);
  4489.                 if pos('foreward', options) <> 0 then
  4490.                     doFFT(ForewardFFT)
  4491.                 else if pos('inverse', options) <> 0 then begin
  4492.                     if pos('without', options) <> 0 then
  4493.                         doFFT(InverseFFT)
  4494.                     else if pos('filter', options) <> 0 then
  4495.                         doFFT(InverseFFTWithFilter)
  4496.                     else doFFT(InverseFFTWithMask)
  4497.                 end else if pos('display', options) <> 0 then
  4498.                     RedisplayPowerSpectrum
  4499.                 else if pos('swap', options) <> 0 then
  4500.                     doSwapQuadrants
  4501.                 else
  4502.                     MacroError('Unrecognized argument');
  4503.             end;
  4504.     end;
  4505.  
  4506.  
  4507.     procedure GetFileInfo; {(path: string, var type:string; var size: integer)}
  4508.     type
  4509.         CharArray = packed array[1..4] of char;
  4510.     var
  4511.         err: OSErr;
  4512.         path: str255;
  4513.         FinderInfo: FInfo;
  4514.         ftype: CharArray;
  4515.         loc1, loc2, f: integer;
  4516.         FileSize : LongInt;
  4517.     begin
  4518.         GetLeftParen;
  4519.         path := GetString;
  4520.         GetComma;
  4521.         loc1 := GetStringVar;
  4522.         GetComma;
  4523.         loc2 := GetVar;
  4524.         GetRightParen;
  4525.         if Token <> DoneT then with MacrosP^ do begin
  4526.             err := GetFInfo(path, 0, FinderInfo);
  4527.             if err = noErr then begin
  4528.                 err := fsopen(path, 0, f);
  4529.                 err := GetEOF(f, FileSize);
  4530.                 if err = noErr then
  4531.                     stack[loc2].value := FileSize
  4532.                 else
  4533.                     stack[loc2].value := -1;
  4534.                 err := fsclose(f);
  4535.                 fType := CharArray(FinderInfo.fdType);
  4536.                 stack[loc1].StringH^^ := concat(ftype[1], ftype[2], ftype[3], ftype[4]);
  4537.             end else begin
  4538.                 stack[loc1].StringH^^ := '';
  4539.                 stack[loc2].value := -1;
  4540.             end;
  4541.         end;
  4542.     end;
  4543.  
  4544.  
  4545.     procedure DoSelectTool;
  4546.     var
  4547.         tType: str255;
  4548.     begin
  4549.         GetLeftParen;
  4550.         tType := GetString;
  4551.         GetRightParen;
  4552.         if token = DoneT then
  4553.             exit(DoSelectTool);
  4554.         MakeLowerCase(tType);
  4555.         PreviousTool := CurrentTool;
  4556.             {left side tools}
  4557.         if pos('magn', tType) <> 0 then
  4558.             CurrentTool := MagnifyingGlass
  4559.         else if pos('grabber', tType) <> 0 then
  4560.             CurrentTool := Grabber
  4561.         else if pos('pencil', tType) <> 0 then
  4562.             CurrentTool := Pencil
  4563.         else if pos('eraser', tType) <> 0 then
  4564.             CurrentTool := Eraser
  4565.         else if pos('brush', tType) <> 0 then
  4566.             CurrentTool := Brush
  4567.         else if pos('drawline', tType) <> 0 then
  4568.             CurrentTool := ruler
  4569.         else if pos('paint', tType) <> 0 then
  4570.             CurrentTool := PaintBucket
  4571.         else if pos('profile', tType) <> 0 then
  4572.             CurrentTool := PlotTool
  4573.         else if pos('wand', tType) <> 0 then
  4574.             CurrentTool := Wand
  4575.         else if pos('angletool', tType) <> 0 then
  4576.             CurrentTool := AngleTool
  4577.             {right side tools}
  4578.         else if pos('rect', tType) <> 0 then
  4579.             CurrentTool := SelectionTool
  4580.         else if pos('oval', tType) <> 0 then
  4581.             CurrentTool := OvalSelectionTool
  4582.         else if pos('poly', tType) <> 0 then
  4583.             CurrentTool := PolygonTool
  4584.         else if pos('freehand', tType) <> 0 then
  4585.             CurrentTool := FreehandTool
  4586.         else if pos('straight', tType) <> 0 then begin
  4587.             CurrentTool := LineTool;
  4588.             LOIType := Straight;
  4589.         end
  4590.         else if pos('freeline', tType) <> 0 then begin
  4591.             CurrentTool := LineTool;
  4592.             LOIType := Freehand;
  4593.         end
  4594.         else if pos('segment', tType) <> 0 then begin
  4595.             CurrentTool := LineTool;
  4596.             LOIType := Segmented;
  4597.         end
  4598.         else if pos('lut', tType) <> 0 then
  4599.             CurrentTool := LUTTool
  4600.         else if pos('text', tType) <> 0 then
  4601.             CurrentTool := TextTool
  4602.         else if pos('spray', tType) <> 0 then
  4603.             CurrentTool := SprayCanTool
  4604.         else if pos('picker', tType) <> 0 then
  4605.             CurrentTool := PickerTool
  4606.         else if pos('cross', tType) <> 0 then
  4607.             CurrentTool := CrossHairTool
  4608.         else begin
  4609.             MacroError('Unrecognized tool name');
  4610.             exit(DoSelectTool);
  4611.         end;
  4612.         isSelectionTool := (CurrentTool = SelectionTool) or (CurrentTool = OvalSelectionTool)
  4613.             or (CurrentTool = PolygonTool) or (CurrentTool = FreehandTool) or (CurrentTool = LineTool);
  4614.         DrawTools;
  4615.         if (not isSelectionTool) and (CurrentTool <> MagnifyingGlass) and
  4616.             (CurrentTool <> Grabber) and (CurrentTool <> Wand) then
  4617.                 KillRoi;
  4618.         with info^ do if RoiShowing then
  4619.             if EqualRect(RoiRect, PicRect) and not isSelectionTool then {if Select All}
  4620.                 KillRoi;
  4621.         if (CurrentTool = SelectionTool) or (CurrentTool = CrossHairTool) then begin
  4622.             InfoMessage := '';
  4623.             if mCount > 0 then
  4624.                 ShowInfo;
  4625.         end;
  4626.         RoiMode := MoveMode;
  4627.         if CurrentTool = LineTool then
  4628.             if (LoiType = Straight) and (LineWidth <> 1) then begin
  4629.                 LineWidth := 1;
  4630.                 UpdateRoiLineWidth;
  4631.                 ShowLineWidth;
  4632.         end;
  4633.     end;
  4634.  
  4635.  
  4636.     procedure DoExit;
  4637.     var
  4638.         reason: str255;
  4639.     begin
  4640.         GetToken;
  4641.         if token = LeftParen then begin
  4642.             reason := GetString;
  4643.             GetRightParen;
  4644.             beep;
  4645.             PutMessage(reason);
  4646.         end else
  4647.           PutTokenBack;
  4648.         token := DoneT;
  4649.     end;
  4650.  
  4651.  
  4652.     procedure DoBinary; {(op:string)}
  4653.         var
  4654.             op: str255;
  4655.     begin
  4656.         GetLeftParen;
  4657.         op := GetString;
  4658.         GetRightParen;
  4659.         if token <> DoneT then begin
  4660.                 MakeLowerCase(op);
  4661.                 if (pos('edm', op) <> 0) or (pos('map', op) <> 0) then begin
  4662.                     MakeEDM(EDMItem);
  4663.                     exit(DoBinary);
  4664.                 end;
  4665.                 if pos('ultimate', op) <> 0 then begin
  4666.                     MakeEDM(UltimateItem);
  4667.                     exit(DoBinary);
  4668.                 end;
  4669.                 if pos('watershed', op) <> 0 then begin
  4670.                     MakeEDM(WatershedItem);
  4671.                     exit(DoBinary);
  4672.                 end;
  4673.                 MacroError('Undefined binary operation');
  4674.             end;
  4675.     end;
  4676.  
  4677.  
  4678.       procedure DoAverageSlices;
  4679.     var
  4680.        FirstSlice, nSlices: LongInt;
  4681.         HasArguments: boolean;
  4682.     begin
  4683.         GetToken;
  4684.         HasArguments := token = LeftParen;
  4685.         PutTokenBack;
  4686.         FirstSlice := 0;
  4687.         nSlices := 0;
  4688.         if HasArguments then begin
  4689.             GetLeftParen;
  4690.             FirstSlice := GetInteger;
  4691.             GetComma;
  4692.             nSlices := GetInteger;
  4693.             GetRightParen;
  4694.         end;
  4695.         if (Token <> DoneT) then
  4696.             AverageSlices(FirstSlice, nSlices);
  4697.       end;
  4698.       
  4699.       
  4700.       procedure ExecuteCommand;
  4701.         var
  4702.             AutoSelectAll: boolean;
  4703.             t: FateTable;  {Needed for MakeSkeleton}
  4704.             okay: boolean;
  4705.             theEvent: EventRecord;
  4706.     begin
  4707.         if Info = NoInfo then
  4708.             if not (MacroCommand in LegalWithoutImage) then begin
  4709.                     MacroError('No image window active');
  4710.                     exit(ExecuteCommand);
  4711.                 end;
  4712.         if DoOption then begin
  4713.                 OptionKeyWasDown := true;
  4714.                 DoOption := false;
  4715.             end;
  4716.         if OpPending then
  4717.             if not (MacroCommand in [CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC, SetOptionC, PasteLiveC, GetRoiC, RequiresC, UndoC]) then begin
  4718.                     KillRoi; {Terminate any pending paste operation.}
  4719.                     RestoreRoi;
  4720.                 end;
  4721.         case MacroCommand of
  4722.             RotateRC, RotateLC: 
  4723.                 DoRotate(MacroCommand);
  4724.             FlipVC: 
  4725.                 FlipOrRotate(FlipVertical);
  4726.             FlipHC: 
  4727.                 FlipOrRotate(FlipHorizontal);
  4728.             CopyC:  begin
  4729.                     FindWhatToCopy;
  4730.                     if WhatToCopy = NothingToCopy then
  4731.                         MacroError('Copy failed')
  4732.                     else
  4733.                         DoCopy;
  4734.                 end;
  4735.             SelectC:
  4736.                 if CurrentWindow = TextKind then
  4737.                     SelectAllText
  4738.                 else begin
  4739.                     StopDigitizing;
  4740.                     SelectAll(true);
  4741.                 end;
  4742.             PasteC: 
  4743.                 DoPaste;
  4744.             ClearC, FillC, InvertC, FrameC: 
  4745.                 with info^ do begin
  4746.                         AutoSelectAll := not RoiShowing;
  4747.                         if AutoSelectAll then
  4748.                             SelectAll(true);
  4749.                         case MacroCommand of
  4750.                             ClearC: 
  4751.                                 DoOperation(EraseOp);
  4752.                             FillC: 
  4753.                                 DoOperation(PaintOp);
  4754.                             InvertC: 
  4755.                                 DoOperation(InvertOp);
  4756.                             FrameC: 
  4757.                                 DoOperation(FrameOp);
  4758.                         end;
  4759.                         UpdateScreen(RoiRect);
  4760.                         if AutoSelectAll then
  4761.                             KillRoi;
  4762.                     end;
  4763.             KillC: 
  4764.                 KillRoi;
  4765.             RestoreC: 
  4766.                 if NoInfo^.RoiType <> NoRoi then
  4767.                     RestoreRoi;
  4768.             AnalyzeC: 
  4769.                 DoAnalyzeParticles;
  4770.             ConvolveC: 
  4771.                 DoConvolve;
  4772.             NextC: 
  4773.                 GetNextWindow;
  4774.             MarkC: 
  4775.                 MarkSelection(mCount);
  4776.             MeasureC:  begin
  4777.                     Measure;
  4778.                     InitCursor;
  4779.                 end;
  4780.             MakeBinC: 
  4781.                 MakeBinary;
  4782.             DitherC: 
  4783.                 Filter(Dither, 0, t);
  4784.             SmoothC: 
  4785.                 if OptionKeyWasDown then
  4786.                     Filter(UnweightedAvg, 0, t)
  4787.                 else
  4788.                     Filter(WeightedAvg, 0, t);
  4789.             SharpenC: 
  4790.                 Filter(fsharpen, 0, t);
  4791.             ShadowC: 
  4792.                 DoShadow;
  4793.             TraceC: 
  4794.                 Filter(EdgeDetect, 0, t);
  4795.             ReduceC: 
  4796.                 Filter(ReduceNoise, 0, t);
  4797.             RedirectC: 
  4798.                 RedirectSampling := GetBooleanArg;
  4799.             ThresholdC: 
  4800.                 SetThreshold;
  4801.             AutoThresholdC: 
  4802.                 AutoThreshold;
  4803.             ResetgmC: 
  4804.                 ResetGrayMap;
  4805.             WaitC: 
  4806.                 DoWait;
  4807.             ResetmC: 
  4808.                 ResetCounter;
  4809.             SetSliceC: 
  4810.                 SetDensitySlice;
  4811.             UndoC: 
  4812.                 DoUndo;
  4813.             SetForeC, SetBackC: 
  4814.                 SetColor;
  4815.             HistoC:  begin
  4816.                     DoHistogram;
  4817.                     DrawHistogram;
  4818.                 end;
  4819.             EnhanceC: 
  4820.                 EnhanceContrast;
  4821.             EqualizeC: 
  4822.                 EqualizeHistogram;
  4823.             ErodeC:  begin
  4824.                     BinaryIterations := 1;
  4825.                     DoErosion;
  4826.                 end;
  4827.             DilateC:  begin
  4828.                     BinaryIterations := 1;
  4829.                     DoDilation;
  4830.                 end;
  4831.             OutlineC: 
  4832.                 filter(OutlineFilter, 0, t);
  4833.             ThinC: 
  4834.                 MakeSkeleton;
  4835.             AddConstC, MulConstC: 
  4836.                 DoConstantArithmetic;
  4837.             RevertC: 
  4838.                 DoRevert;
  4839.             BeepC: 
  4840.                 Beep;
  4841.             NopC: 
  4842.                 ;
  4843.             MakeC, MakeOvalC: 
  4844.                 MakeRoi;
  4845.             MoveC: 
  4846.                 MoveRoi;
  4847.             InsetC: 
  4848.                 InsetRoi;
  4849.             MoveToC: 
  4850.                 DoMoveTo;
  4851.             DrawTextC, WriteC, WritelnC, ShowMsgC: 
  4852.                 OutputText;
  4853.             SetFontC: 
  4854.                 SetFont;
  4855.             SetFontSizeC: 
  4856.                 SetFontSize;
  4857.             SetTextC: 
  4858.                 SetText;
  4859.             DrawNumC: 
  4860.                 DrawNumber;
  4861.             ExitC:
  4862.                 DoExit; 
  4863.             GetPicSizeC: 
  4864.                 GetPicSize;
  4865.             PutMsgC: 
  4866.                 DoPutMessage;
  4867.             GetRoiC: 
  4868.                 GetRoi;
  4869.             MakeNewC: 
  4870.                 DoMakeNewWindow;
  4871.             DrawScaleC: 
  4872.                 if info^.RoiShowing then begin
  4873.                         DrawScale;
  4874.                         UpdatePicWindow
  4875.                     end
  4876.                 else
  4877.                     MacroError('No Selection');
  4878.             SetPaletteC: 
  4879.                 DoSetPalette;
  4880.             OpenC, ImportC: 
  4881.                 DoOpenImage;
  4882.             SetImportC: 
  4883.                 SetImportAttributes;
  4884.             SetMinMaxC: 
  4885.                 SetImportMinMax;
  4886.             SetCustomC: 
  4887.                 SetCustomImport;
  4888.             SelectPicC, ChoosePicC: 
  4889.                 SelectPic;
  4890.             SetPicNameC: 
  4891.                 SetPicName;
  4892.             ApplyLutC: 
  4893.                 ApplyLookupTable;
  4894.             SetSizeC: 
  4895.                 SetNewSize;
  4896.             SaveC: 
  4897.                 DoSave;
  4898.             SaveAllC: 
  4899.                 SaveAll;
  4900.             SaveAsC: 
  4901.                 DoSaveAs;
  4902.             CopyResultsC: 
  4903.                 DoCopyResults;
  4904.             CloseC, DisposeC: 
  4905.                 CloseWindow;
  4906.             DisposeAllC: 
  4907.                 DisposeAll;
  4908.             DupC: 
  4909.                 DoDuplicate;
  4910.             GetInfoC: 
  4911.                 GetInfo;
  4912.             PrintC: 
  4913.                 DoPrint;
  4914.             LineToC: 
  4915.                 DoLineTo;
  4916.             GetLineC: 
  4917.                 DoGetLine;
  4918.             ShowPasteC: 
  4919.                 if PasteControl = nil then
  4920.                     ShowPasteControl
  4921.                 else
  4922.                     BringToFront(PasteControl);
  4923.             ChannelC: 
  4924.                 SetChannel;
  4925.             ColumnC, PlotProfileC:  begin
  4926.                     PlotDensityProfile;
  4927.                     if PlotWindow <> nil then
  4928.                         UpdatePlotWindow;
  4929.                 end;
  4930.             ScaleC, ScaleSelectionC: 
  4931.                 DoScaleAndRotate;
  4932.             SetOptionC: 
  4933.                 DoOption := true;
  4934.             SetLabelsC: 
  4935.                 DrawPlotLabels := GetBooleanArg;
  4936.             SetPlotScaleC: 
  4937.                 SetPlotScale;
  4938.             SetDimC: 
  4939.                 SetPlotDimensions;
  4940.             GetResultsC: 
  4941.                 GetResults;
  4942.             CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC: 
  4943.                 DoPasteOperation;
  4944.             ScaleMathC: 
  4945.                 ScaleArithmetic := GetBooleanArg;
  4946.             InvertYC: 
  4947.                 InvertYCoordinates := GetBooleanArg;
  4948.             SetWidthC: 
  4949.                 SetWidth;
  4950.             ShowResultsC:  begin
  4951.                     ShowResults;
  4952.                     UpdateList
  4953.                 end;
  4954.             StartC: 
  4955.                 StartDigitizing;
  4956.             StopC: 
  4957.                 StopDigitizing;
  4958.             CaptureC: 
  4959.                 CaptureOneFrame;
  4960.             GetRowC, PutRowC, GetColumnC, PutColumnC: 
  4961.                 GetOrPutLineOrColumn;
  4962.             PlotXYZC: 
  4963.                 PlotXYZ;
  4964.             IncludeC: 
  4965.                 IncludeHoles := GetBooleanArg;
  4966.             AutoC: 
  4967.                 WandAutoMeasure := GetBooleanArg;
  4968.             LabelC: 
  4969.                 LabelParticles := GetBooleanArg;
  4970.             OutlineParticlesC: 
  4971.                 OutlineParticles := GetBooleanArg;
  4972.             IgnoreC: 
  4973.                 IgnoreParticlesTouchingEdge := GetBooleanArg;
  4974.             AdjustC: 
  4975.                 WandAdjustAreas := GetBooleanArg;
  4976.             SetParticleSizeC: 
  4977.                 SetParticleSize;
  4978.             SetPrecisionC: 
  4979.                 SetPrecision;
  4980.             PutPixelC: 
  4981.                 DoPutPixel;
  4982.             ScalingOptionsC: 
  4983.                 SetScaling;
  4984.             SetExportC: 
  4985.                 SetExportMode;
  4986.             ExportC: 
  4987.                 DoExport;
  4988.             ChangeC: 
  4989.                 DoChangeValues;
  4990.             UpdateResultsC:  begin
  4991.                     ShowInfo;
  4992.                     DeleteLines(mCount, mCount);
  4993.                     AppendResults;
  4994.                 end;
  4995.             TileC: 
  4996.                 TileImages;
  4997.             SetMajorC, SetMinorC, SetUser1C, SetUser2C: 
  4998.                 SetLabel;
  4999.             GetMouseC: 
  5000.                 DoGetMouse;
  5001.             SelectSliceC, ChooseSliceC, AddSliceC, DeleteSliceC, ResliceC:  begin
  5002.                     if info^.StackInfo = nil then
  5003.                         MacroError('No stack');
  5004.                     if token <> DoneT then
  5005.                         case MacroCommand of
  5006.                             SelectSliceC, ChooseSliceC: 
  5007.                                 DoSelectSlice;
  5008.                             AddSliceC: 
  5009.                                 okay := AddSlice(true);
  5010.                             DeleteSliceC: 
  5011.                                 DeleteSlice;
  5012.                             ResliceC: 
  5013.                                 Reslice;
  5014.                         end;
  5015.                 end;
  5016.             MakeStackC: 
  5017.                 MakeNewStack;
  5018.             AverageFramesC: 
  5019.                 DoAverageFrames;
  5020.             TriggerC: 
  5021.                 WaitForTrigger;
  5022.             MakeLineC: 
  5023.                 MakeLineRoi;
  5024.             GetTimeC: 
  5025.                 DoGetTime;
  5026.             SetScaleC: 
  5027.                 DoSetScale;
  5028.             SaveStateC: 
  5029.                 SaveState;
  5030.             RestoreStateC: 
  5031.                 RestoreState;
  5032.             SetCounterC: 
  5033.                 SetCounter;
  5034.             UpdateLutC: 
  5035.                 DoUpdateLUT;
  5036.             SetCountC: 
  5037.                 SetErosionDilationCount;
  5038.             PropagateLutC: 
  5039.                 DoPropagate(1);
  5040.             PropagateSpatialC: 
  5041.                 DoPropagate(2);
  5042.             PropagateDensityC: 
  5043.                 DoPropagate(3);
  5044.             SetSpacingC: 
  5045.                 SetSliceSpacing;
  5046.             RequiresC: 
  5047.                 CheckVersion;
  5048.             SetOptionsC: 
  5049.                 SetOptions;
  5050.             SubtractBackgroundC: 
  5051.                 SubtractBackground;
  5052.             MoveWindowC: 
  5053.                 MoveCurrentWindow;
  5054.             UserCodeC: 
  5055.                 DoUserCode;
  5056.             InvertLutC:  begin
  5057.                     InvertPalette;
  5058.                     UpdateLUT;
  5059.                 end;
  5060.             OpenSerialC: 
  5061.                 OpenSerial;
  5062.             PutSerialC: 
  5063.                 PutSerial;
  5064.             SetCursorC: 
  5065.                 DoSetCursor;
  5066.             SetVideoC: 
  5067.                 SetVideoOptions;
  5068.             AcquireC: 
  5069.                 DoAcquire;
  5070.             CallFilterC: 
  5071.                 CallFilterPlugin;
  5072.             PhotoModeC: 
  5073.                 DoPhotoMode;
  5074.             RGBToIndexedC: 
  5075.                 RGBToIndexed;
  5076.             SurfacePlotC: 
  5077.                 PlotSurface;
  5078.             SelectWindowC: 
  5079.                 DoSelectWindow;
  5080.             NewTextWindowC: 
  5081.                 DoNewTextWindow;
  5082.             CaptureColorC: 
  5083.                 CaptureColor;
  5084.             GetThresholdC: 
  5085.                 GetThreshold;
  5086.             AverageSlicesC: 
  5087.                 DoAverageSlices;
  5088.             SortPaletteC: 
  5089.                 SortPalette;
  5090.             ProjectC: 
  5091.                 DoProject;
  5092.             ScaleConvolutionsC: 
  5093.                 ScaleConvolutions := GetBooleanArg;
  5094.             ImageMathC: 
  5095.                 ImageMath;
  5096.             PasteLiveC: 
  5097.                 PasteLive;
  5098.             GetPlotDataC: 
  5099.                 GetPlotData;
  5100.             DeleteC: 
  5101.                 DoDelete;
  5102.             GetScaleC: 
  5103.                 GetScale;
  5104.             AutoOutlineC: 
  5105.                 DoAutoOutline;
  5106.             FilterC: 
  5107.                 DoFilter;
  5108.             SetSaveAsC:
  5109.                 SetSaveAsMode;
  5110.             CalibrateC:
  5111.                 DoCalibrate;
  5112.             CallExportC:
  5113.                 CallExportPlugin;
  5114.             IndexedToRGBC:
  5115.                 ConvertEightBitColorToRGB;
  5116.             MakeMovieC:
  5117.                 DoMakeMovie;
  5118.        SetProjectionC:
  5119.           SetProjection;
  5120.        GetHistogramC:
  5121.               DoGetHistogram;
  5122.           fftC:
  5123.               doFFTMacro;
  5124.           GetFileInfoC:
  5125.               GetFileInfo;
  5126.           SelectToolC:
  5127.               DoSelectTool;
  5128.           BinaryC:
  5129.               DoBinary;
  5130.         end; {case}
  5131.         OptionKeyWasDown := false;
  5132.         if not macro then begin
  5133.                 Token := DoneT;
  5134.                 KillRoi;
  5135.             end;
  5136.         if TickCount > MacroTicks then begin
  5137.                 if EventAvail(everyEvent, theEvent) then; {Allows background tasks to run}
  5138.                 if CommandPeriod then begin
  5139.                         Token := DoneT;
  5140.                         KillRoi;
  5141.                     end;
  5142.                 MacroTicks := TickCount + 15;
  5143.             end;
  5144.     end;
  5145.  
  5146.  
  5147.     procedure DoCompoundStatement;
  5148.     begin
  5149.         if token <> BeginT then
  5150.             MacroError('"begin" expected');
  5151.         GetToken;
  5152.         while (token <> endT) and (token <> DoneT) do begin
  5153.                 DoStatement;
  5154.                 GetToken;
  5155.                 if Token = SemiColon then
  5156.                     GetToken
  5157.                 else if token <> EndT then
  5158.                     MacroError(EndExpected);
  5159.             end;
  5160.     end;
  5161.  
  5162.  
  5163.     procedure SkipCompoundStatement;
  5164.         var
  5165.             count: integer;
  5166.     begin
  5167.         count := 1;
  5168.         repeat
  5169.             GetToken;
  5170.             case token of
  5171.                 beginT: 
  5172.                     count := count + 1;
  5173.                 endT: 
  5174.                     count := count - 1;
  5175.                 DoneT:  begin
  5176.                         MacroError('"end" expected');
  5177.                         exit(SkipCompoundStatement);
  5178.                     end;
  5179.                 otherwise
  5180.             end; {case}
  5181.         until count = 0;
  5182.     end;
  5183.  
  5184.  
  5185.     procedure DoDeclarations;
  5186.     begin
  5187.         if token = SemiColon then
  5188.             GetToken;
  5189.         if token = VarT then begin
  5190.                 GetToken;
  5191.                 while ((token = Identifier) or (token = variable) or (token = StringVariable)) and (Token <> DoneT) do
  5192.                     DoDeclaration;
  5193.             end;
  5194.     end;
  5195.  
  5196.  
  5197.     procedure DoFor;
  5198.         var
  5199.             SavePC, StackLoc: integer;
  5200.             StartValue, EndValue, i: LongInt;
  5201.     begin
  5202.         StackLoc := GetVar;
  5203.         GetToken;
  5204.         if token <> AssignOp then begin
  5205.                 MacroError('":=" expected');
  5206.                 exit(DoFor);
  5207.             end;
  5208.         StartValue := GetInteger;
  5209.         if token = DoneT then
  5210.             exit(DoFor);
  5211.         GetToken;
  5212.         if token <> ToT then begin
  5213.                 MacroError('"to" expected');
  5214.                 exit(DoFor);
  5215.             end;
  5216.         EndValue := GetInteger;
  5217.         if token = DoneT then
  5218.             exit(DoFor);
  5219.         GetToken;
  5220.         if token <> DoT then begin
  5221.                 MacroError(DoExpected);
  5222.                 exit(DoFor);
  5223.             end;
  5224.         SavePC := pc;
  5225.         if StartValue > EndValue then begin
  5226.                 GetToken;
  5227.                 SkipStatement
  5228.             end
  5229.         else
  5230.             for i := StartValue to EndValue do
  5231.                 with MacrosP^ do begin
  5232.                         Stack[StackLoc].value := i;
  5233.                         pc := SavePC;
  5234.                         GetToken;
  5235.                         DoStatement;
  5236.                         LoopCounter := LoopCounter + 1;
  5237.                         if LoopCounter >= MaxLoopCount then begin
  5238.                             if CommandPeriod then
  5239.                                 token := DoneT;
  5240.                             LoopCounter := 0;
  5241.                         end;
  5242.                         if Token = DoneT then
  5243.                             leave;
  5244.                         if Digitizing then
  5245.                             DoCapture;
  5246.                     end;
  5247.     end;
  5248.  
  5249.  
  5250.     procedure SkipFor;
  5251.     begin
  5252.         GetToken;
  5253.         SkipPartialStatement;
  5254.         GetToken;
  5255.         if token <> doT then
  5256.             MacroError(DoExpected);
  5257.         GetToken;
  5258.         SkipStatement
  5259.     end;
  5260.  
  5261.  
  5262.     procedure DoAssignment;
  5263.         var
  5264.             SaveStackLoc: integer;
  5265.     begin
  5266.         SaveStackLoc := TokenStackLoc;
  5267.         GetToken;
  5268.         if token <> AssignOp then begin
  5269.                 MacroError('":=" expected');
  5270.                 exit(DoAssignment);
  5271.             end;
  5272.         MacrosP^.stack[SaveStackLoc].value := GetBooleanExpression;
  5273.     end;
  5274.  
  5275.  
  5276.     procedure DoStringAssignment;
  5277.         var
  5278.             SaveStackLoc: integer;
  5279.             str: Str255;
  5280.     begin
  5281.         SaveStackLoc := TokenStackLoc;
  5282.         GetToken;
  5283.         if token <> AssignOp then begin
  5284.                 MacroError('":=" expected');
  5285.                 exit(DoStringAssignment);
  5286.             end;
  5287.         str := GetString;
  5288.         if token <> DoneT then
  5289.             with MacrosP^.stack[SaveStackLoc] do
  5290.                 if StringH <> nil then
  5291.                     StringH^^ := str;
  5292.     end;
  5293.  
  5294.  
  5295.     procedure SkipPartialStatement;
  5296.         var
  5297.             done: Boolean;
  5298.     begin
  5299.         done := token = DoneT;
  5300.         while not done do begin
  5301.                 case token of
  5302.                     ThenT, DoT, SemiColon, EndT, ElseT, UntilT:  begin
  5303.                             PutTokenBack;
  5304.                             done := true;
  5305.                         end;
  5306.                     DoneT, BeginT, ForT, IfT, WhileT, RepeatT:  begin
  5307.                             MacroError('end of statement expected');
  5308.                             done := true;
  5309.                         end;
  5310.                     otherwise
  5311.                         GetToken;
  5312.                 end;
  5313.             end;
  5314.     end;
  5315.  
  5316.  
  5317.     procedure DoIf;
  5318.         var
  5319.             isTrue: boolean;
  5320.     begin
  5321.         isTrue := GetBoolean;
  5322.         GetToken;
  5323.         if token <> ThenT then
  5324.             MacroError(ThenExpected);
  5325.         if isTrue then begin
  5326.                 GetToken;
  5327.                 DoStatement
  5328.             end
  5329.         else begin
  5330.                 GetToken;
  5331.                 SkipStatement;
  5332.             end;
  5333.         GetToken;
  5334.         if token = elseT then begin
  5335.                 if isTrue then begin
  5336.                         GetToken;
  5337.                         SkipStatement
  5338.                     end
  5339.                 else begin
  5340.                         GetToken;
  5341.                         DoStatement;
  5342.                     end;
  5343.             end
  5344.         else
  5345.             PutTokenBack;
  5346.     end;
  5347.  
  5348.  
  5349.     procedure SkipIf;
  5350.     begin
  5351.         GetToken;
  5352.         SkipPartialStatement;
  5353.         GetToken;
  5354.         if token <> thenT then
  5355.             MacroError(ThenExpected);
  5356.         GetToken;
  5357.         SkipStatement;
  5358.         GetToken;
  5359.         if token <> elseT then
  5360.             PutTokenBack
  5361.         else begin
  5362.                 GetToken;
  5363.                 SkipStatement
  5364.             end
  5365.     end;
  5366.  
  5367.  
  5368.     procedure DoWhile;
  5369.         var
  5370.             isTrue: boolean;
  5371.             SavePC: integer;
  5372.     begin
  5373.         SavePC := pc;
  5374.         repeat
  5375.             pc := SavePC;
  5376.             isTrue := GetBoolean;
  5377.             GetToken;
  5378.             if token <> doT then
  5379.                 MacroError(DoExpected);
  5380.             if isTrue then begin
  5381.                     GetToken;
  5382.                     DoStatement
  5383.                 end
  5384.             else begin
  5385.                     GetToken;
  5386.                     SkipStatement;
  5387.                 end;
  5388.             if Digitizing then
  5389.                 DoCapture;
  5390.             LoopCounter := LoopCounter + 1;
  5391.             if LoopCounter >= MaxLoopCount then begin
  5392.                 if CommandPeriod then
  5393.                     token := DoneT;
  5394.                 LoopCounter := 0;
  5395.             end;
  5396.         until not isTrue or (Token = DoneT);
  5397.     end;
  5398.  
  5399.  
  5400.     procedure SkipWhile;
  5401.     begin
  5402.         GetToken;
  5403.         SkipPartialStatement;
  5404.         GetToken;
  5405.         if token <> doT then
  5406.             MacroError(DoExpected);
  5407.         GetToken;
  5408.         SkipStatement
  5409.     end;
  5410.  
  5411.  
  5412.     procedure DoRepeat;
  5413.         var
  5414.             isTrue: boolean;
  5415.             SavePC: integer;
  5416.     begin
  5417.         SavePC := pc;
  5418.         isTrue := true;
  5419.         repeat
  5420.             pc := SavePC;
  5421.             GetToken;
  5422.             while (token <> untilT) and (token <> DoneT) do begin
  5423.                     DoStatement;
  5424.                     GetToken;
  5425.                     if Token = SemiColon then
  5426.                         GetToken;
  5427.                     LoopCounter := LoopCounter + 1;
  5428.                     if LoopCounter >= MaxLoopCount then begin
  5429.                         if CommandPeriod then
  5430.                             token := DoneT;
  5431.                         LoopCounter := 0;
  5432.                     end;
  5433.                 end;
  5434.             if token <> untilT then
  5435.                 MacroError(UntilExpected);
  5436.             isTrue := GetBoolean;
  5437.             if Digitizing then
  5438.                 DoCapture;
  5439.         until isTrue or (Token = DoneT);
  5440.     end;
  5441.  
  5442.  
  5443.     procedure SkipRepeat;
  5444.     begin
  5445.         GetToken;
  5446.         while (token <> untilT) and (token <> DoneT) do begin
  5447.                 SkipStatement;
  5448.                 GetToken;
  5449.                 if token = SemiColon then
  5450.                     GetToken
  5451.                 else if token <> UntilT then
  5452.                     MacroError(UntilExpected);
  5453.             end;
  5454.         GetToken;
  5455.         SkipPartialStatement;
  5456.     end;
  5457.  
  5458.  
  5459.     procedure DoArrayAssignment;
  5460.         var
  5461.             SaveArrayType: ArrayType;
  5462.             index, LutValue, PixelValue, RegisterValue: LongInt;
  5463.             SyncChannel: integer;
  5464.     begin
  5465.         SaveArrayType := ArrayType(MacroCommand);
  5466.         GetToken;
  5467.         if token <> LeftBracket then
  5468.             MacroError('"[" expected');
  5469.         Index := GetInteger;
  5470.         GetToken;
  5471.         if token <> RightBracket then
  5472.             MacroError('"]" expected');
  5473.         GetToken;
  5474.         if token <> AssignOp then
  5475.             MacroError('":=" expected');
  5476.  
  5477.         if SaveArrayType = BufferA then begin
  5478.                 CheckIndex(index, 0, MaxLine - 1);
  5479.                 PixelValue := GetInteger;
  5480.                 RangeCheck(PixelValue);
  5481.                 if token <> DoneT then
  5482.                     MacrosP^.aLine[index] := PixelValue;
  5483.                 exit(DoArrayAssignment);
  5484.             end;
  5485.  
  5486.         if SaveArrayType in [RedLutA, BlueLutA, GreenLutA] then begin
  5487.                 RangeCheck(index);
  5488.                 LutValue := GetInteger;
  5489.                 RangeCheck(LutValue);
  5490.                 if token <> DoneT then
  5491.                     with info^.cTable[index].rgb do
  5492.                         case SaveArrayType of
  5493.                             RedLutA: 
  5494.                                 red := bsl(LutValue, 8);
  5495.                             GreenLutA: 
  5496.                                 green := bsl(LutValue, 8);
  5497.                             BlueLutA: 
  5498.                                 blue := bsl(LutValue, 8);
  5499.                         end;
  5500.                 exit(DoArrayAssignment);
  5501.             end;
  5502.  
  5503.         if SaveArrayType = ScionA then begin
  5504.                 if framegrabber <> ScionLG3 then
  5505.                     MacroError('No Scion LG-3');
  5506.                 if Token <> DoneT then
  5507.                     CheckIndex(index, 1, 4);
  5508.                 if Token = DoneT then
  5509.                     exit(DoArrayAssignment);
  5510.                 if index = 3 then
  5511.                     MacroError('DataIn is read-only');
  5512.                 RegisterValue := GetInteger;
  5513.                 if token <> DoneT then begin
  5514.                         if RegisterValue < 0 then
  5515.                             RegisterValue := 0;
  5516.                         if RegisterValue > 255 then
  5517.                             RegisterValue := 255;
  5518.                         case index of
  5519.                             1:  begin
  5520.                                     LG3DacA := RegisterValue;
  5521.                                     DacAReg^ := LG3DacA
  5522.                                 end;
  5523.                             2:  begin
  5524.                                     LG3DacB := RegisterValue;
  5525.                                     DacBReg^ := LG3DacB
  5526.                                 end;
  5527.                             4:  begin
  5528.                                     LG3DataOut := band(RegisterValue, $f);
  5529.                                     if SyncMode = SeparateSync then
  5530.                                         SyncChannel := 3
  5531.                                     else
  5532.                                         SyncChannel := VideoChannel;
  5533.                                     ChannelReg^ := bor(LG3DataOut, bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
  5534.                                 end;
  5535.                         end; {case}
  5536.                     end;
  5537.                 exit(DoArrayAssignment);
  5538.             end;
  5539.  
  5540.         if SaveArrayType = PlotDataA then begin
  5541.                 CheckIndex(index, 0, MaxLine - 1);
  5542.                 PlotData^[index] := GetExpression;
  5543.                 exit(DoArrayAssignment);
  5544.             end;
  5545.  
  5546.         CheckIndex(index, 1, MaxMeasurements);
  5547.         if token <> DoneT then
  5548.             case SaveArrayType of
  5549.                 rAreaA: 
  5550.                     mArea^[Index] := GetExpression;
  5551.                 rMeanA: 
  5552.                     mean^[Index] := GetExpression;
  5553.                 rStdDevA: 
  5554.                     sd^[Index] := GetExpression;
  5555.                 rXA: 
  5556.                     xcenter^[Index] := GetExpression;
  5557.                 rYA: 
  5558.                     ycenter^[Index] := GetExpression;
  5559.                 rLengthA: 
  5560.                     plength^[Index] := GetExpression;
  5561.                 rMinA: 
  5562.                     mMin^[Index] := GetExpression;
  5563.                 rMaxA: 
  5564.                     mMax^[Index] := GetExpression;
  5565.                 rMajorA: 
  5566.                     MajorAxis^[Index] := GetExpression;
  5567.                 rMinorA: 
  5568.                     MinorAxis^[Index] := GetExpression;
  5569.                 rAngleA: 
  5570.                     orientation^[Index] := GetExpression;
  5571.                 rUser1A: 
  5572.                     User1^[Index] := GetExpression;
  5573.                 rUser2A: 
  5574.                     User2^[Index] := GetExpression;
  5575.                 otherwise
  5576.                     MacroError('Read-only array');
  5577.             end; {case}
  5578.     end;
  5579.  
  5580.  
  5581.     procedure PushArguments (var nArgs: integer);
  5582.         var
  5583.             arg: array[1..MaxArgs] of extended;
  5584.             StringArg: array[1..MaxArgs] of boolean;
  5585.             i, nStringArgs: integer;
  5586.             TempName: SymbolType;
  5587.     begin
  5588.         nArgs := 0;
  5589.         nStringArgs := 0;
  5590.         GetToken;
  5591.         while token in [Variable, StringVariable, StringLiteral, NumericLiteral, TrueT, FalseT, FunctionT, UserFunctionT, StringFunctionT, ArrayT, comma, MinusOp, LeftParen] do begin
  5592.                 if token = comma then
  5593.                     GetToken;
  5594.                 if nArgs < MaxArgs then
  5595.                     nArgs := nArgs + 1
  5596.                 else
  5597.                     MacroError('Too many arguments');
  5598.                 if (token = StringVariable) or (token = StringLiteral) or (token = StringFunctionT) then begin
  5599.                         nStringArgs := nStringArgs + 1;
  5600.                         arg[nArgs] := 0.0;
  5601.                         StringArg[nArgs] := true;
  5602.                         if token = StringFunctionT then
  5603.                             TokenStr := DoStringFunction;
  5604.                     end
  5605.                 else begin
  5606.                         PutTokenBack;
  5607.                         arg[nArgs] := GetBooleanExpression;
  5608.                         StringArg[nArgs] := false;
  5609.                     end;
  5610.                 if nStringArgs > 1 then
  5611.                     MacroError('No more than one string argument allowed');
  5612.                 GetToken;
  5613.             end;
  5614.         if token <> RightParen then
  5615.             MacroError(RightParenExpected);
  5616.         for i := 1 to nArgs do begin
  5617.                 if TopOfStack < MaxMacroStackSize then
  5618.                     TopOfStack := TopOfStack + 1
  5619.                 else
  5620.                     MacroError(StackOverflow);
  5621.                 with MacrosP^.stack[TopOfStack] do begin
  5622.                         value := arg[i];
  5623.                         StringH := nil;
  5624.                         if StringArg[i] then begin
  5625.                                 vType := StringVar;
  5626.                                 StringsAllocated := true;
  5627.                                 StringH := str255H(NewHandle(SizeOf(str255)));
  5628.                                 if StringH = nil then begin
  5629.                                         MacroError('Out of memory');
  5630.                                         Token := DoneT
  5631.                                     end
  5632.                                 else
  5633.                                     StringH^^ := TokenStr;
  5634.                             end
  5635.                         else
  5636.                             vType := RealVar;
  5637.                         value := arg[i];
  5638.                     end;
  5639.             end;
  5640.     end;
  5641.  
  5642.  
  5643.     procedure PushFunctionResult(SymbolLoc: integer; var ReturnValueLoc: integer);
  5644.         var
  5645.             StackLoc: integer;
  5646.     begin
  5647.         if TopOfStack >= MaxMacroStackSize then begin
  5648.                 MacroError(StackOverflow);
  5649.                 exit(PushFunctionResult);
  5650.             end;
  5651.         TopOfStack := TopOfStack + 1;
  5652.         ReturnValueLoc := TopOfStack;
  5653.         with MacrosP^.stack[TopOfStack] do begin
  5654.                 SymbolTableIndex := SymbolLoc;
  5655.                 value := 0.0;
  5656.                 StringH := nil;
  5657.             end;
  5658.         with macrosP^.stack[TopOfStack] do
  5659.             case token of
  5660.                 IntegerT: 
  5661.                     vType := IntVar;
  5662.                 RealT: 
  5663.                     vType := RealVar;
  5664.                 BooleanT: 
  5665.                     vType := BooleanVar;
  5666.                 StringT:  begin
  5667.                         vType := StringVar;
  5668.                         StringH := str255H(NewHandle(SizeOf(str255)));
  5669.                         StringsAllocated := true;
  5670.                         if StringH = nil then begin
  5671.                                 MacroError('Out of memory');
  5672.                                 Token := DoneT
  5673.                             end
  5674.                         else
  5675.                             StringH^^ := '';
  5676.                     end;
  5677.                 otherwise
  5678.             end;
  5679.     end;
  5680.  
  5681.  
  5682.     procedure DoUserFunction;
  5683.         var
  5684.             SavePC, SavePCStart, NewPCStart, SaveStackLoc, nArgs, i: integer;
  5685.             SaveSymbolTableLoc, ReturnValueLoc: integer;
  5686.             SaveName, NewFuncName: SymbolType;
  5687.             SaveStringsAllocated: boolean;
  5688.     begin
  5689.         NewPCStart := TokenLoc;
  5690.         NewFuncName := TokenSymbol;
  5691.         SaveStackLoc := TopOfStack;
  5692.         SaveSymbolTableLoc := SymbolTableLoc;
  5693.         SaveStringsAllocated := StringsAllocated;
  5694.         StringsAllocated := false;
  5695.         GetToken;
  5696.         if token = LeftParen then
  5697.             PushArguments(nArgs)
  5698.         else begin
  5699.                 nArgs := 0;
  5700.                 PutTokenBack;
  5701.             end;
  5702.         SavePCStart := PCStart;
  5703.         PCStart := NewPCStart;
  5704.         LineStartPC := NewPCStart - 1;
  5705.         SaveName := MacroOrProcName;
  5706.         MacroOrProcName := NewFuncName;
  5707.         SavePC := pc;
  5708.         pc := pcStart;
  5709.         if nArgs > 0 then begin
  5710.                 GetLeftParen;
  5711.                 i := 0;
  5712.                 GetToken;
  5713.                 while token in [Identifier, Variable, StringVariable, comma, colon, SemiColon, RealT, IntegerT, BooleanT, StringT] do begin
  5714.                         if (token = Identifier) or (token = Variable) or (token = StringVariable) then begin
  5715.                                 if i < nArgs then
  5716.                                     i := i + 1
  5717.                                 else
  5718.                                     MacroError('Too many formal arguments');
  5719.                                 MacrosP^.stack[SaveStackLoc + i].SymbolTableIndex := SymbolTableloc;
  5720.                             end;
  5721.                         GetToken;
  5722.                     end;
  5723.                 if Token = VarT then
  5724.                     MacroError('VAR parameters not supported');
  5725.                 if i < nArgs then
  5726.                     MacroError('Too few formal arguments');
  5727.                 if token <> RightParen then
  5728.                     MacroError(RightParenExpected);
  5729.             end;
  5730.         GetToken;
  5731.         if token <> colon then
  5732.             MacroError('":" expected');
  5733.         GetToken;
  5734.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) and (token <> StringT) then
  5735.             MacroError('"integer", "real", "boolean" or "string" expected');
  5736.         PushFunctionResult(SaveSymbolTableLoc, ReturnValueLoc);
  5737.         GetToken;
  5738.         if (token = LeftParen) and (nArgs = 0) then
  5739.             MacroError('Arguments not expected');
  5740.         DoDeclarations;
  5741.         DoCompoundStatement;
  5742.         pc := SavePC;
  5743.         with MacrosP^.stack[ReturnValueLoc] do begin
  5744.       {Get return value from stack}
  5745.             if (vType = StringVar) and (StringH <> nil) then begin
  5746.                 TokenStr := StringH^^;
  5747.                 TokenValue := 0.0;
  5748.             end else begin
  5749.                 TokenValue := value;
  5750.                 TokenStr := 'No return string';
  5751.             end;
  5752.         end;
  5753.         if StringsAllocated then
  5754.             DeallocateStrings(SaveStackLoc + 1, TopOfStack);
  5755.         StringsAllocated := SaveStringsAllocated;
  5756.         TopOfStack := SaveStackLoc;
  5757.         pcStart := SavePCStart;
  5758.         MacroOrProcName := SaveName;
  5759.     end; {DoUserFunction}
  5760.  
  5761.  
  5762.     procedure DoProcedure;
  5763.         var
  5764.             SavePC, SavePCStart, NewPCStart, SaveStackLoc, nArgs, i: integer;
  5765.             SaveProcName, NewProcName: SymbolType;
  5766.             SaveStringsAllocated: boolean;
  5767.     begin
  5768.         NewPCStart := TokenLoc;
  5769.         NewProcName := TokenSymbol;
  5770.         SaveStackLoc := TopOfStack;
  5771.         SaveStringsAllocated := StringsAllocated;
  5772.         StringsAllocated := false;
  5773.         GetToken;
  5774.         if token = LeftParen then
  5775.             PushArguments(nArgs)
  5776.         else begin
  5777.                 nArgs := 0;
  5778.                 PutTokenBack;
  5779.             end;
  5780.         SavePCStart := PCStart;
  5781.         PCStart := NewPCStart;
  5782.         LineStartPC := NewPCStart - 1;
  5783.         SaveProcName := MacroOrProcName;
  5784.         MacroOrProcName := NewProcName;
  5785.         SavePC := pc;
  5786.         pc := pcStart;
  5787.         if nArgs > 0 then begin
  5788.                 GetLeftParen;
  5789.                 i := 0;
  5790.                 GetToken;
  5791.                 while token in [Identifier, Variable, StringVariable, comma, colon, SemiColon, RealT, IntegerT, BooleanT, StringT] do begin
  5792.                         if (token = Identifier) or (token = Variable) or (token = StringVariable) then begin
  5793.                                 if i < nArgs then
  5794.                                     i := i + 1
  5795.                                 else
  5796.                                     MacroError('Too many formal arguments');
  5797.                                 MacrosP^.stack[SaveStackLoc + i].SymbolTableIndex := SymbolTableloc;
  5798.                             end;
  5799.                         GetToken;
  5800.                     end;
  5801.                 if Token = VarT then
  5802.                     MacroError('VAR parameters not supported');
  5803.                 if i < nArgs then
  5804.                     MacroError('Too few formal arguments');
  5805.                 if token <> RightParen then
  5806.                     MacroError(RightParenExpected);
  5807.             end;
  5808.         GetToken;
  5809.         if (token = LeftParen) and (nArgs = 0) then
  5810.             MacroError('Arguments not expected');
  5811.         DoDeclarations;
  5812.         DoCompoundStatement;
  5813.         pc := SavePC;
  5814.         if StringsAllocated then
  5815.             DeallocateStrings(SaveStackLoc + 1, TopOfStack);
  5816.         StringsAllocated := SaveStringsAllocated;
  5817.         TopOfStack := SaveStackLoc;
  5818.         pcStart := SavePCStart;
  5819.         MacroOrProcName := SaveProcName;
  5820.     end;
  5821.  
  5822.  
  5823.     procedure CannotBeginWithThis;
  5824.         var
  5825.             str: str255;
  5826.     begin
  5827.         str := '';
  5828.         ConvertTokenToString(str);
  5829.         MacroError(concat('Statement cannot begin with ', '"', str, '"'));
  5830.     end;
  5831.     
  5832.     
  5833.     procedure DoFunctionAssignment;
  5834.         var
  5835.             SaveStackLoc: integer;
  5836.             value: extended;
  5837.     begin
  5838.         LookupVariable;
  5839.         SaveStackLoc := TokenStackLoc;
  5840.         GetToken;
  5841.         if token <> AssignOp then begin
  5842.                 MacroError('":=" expected');
  5843.                 exit(DoFunctionAssignment);
  5844.             end;
  5845.         with MacrosP^.stack[SaveStackLoc] do begin
  5846.             if (vType =StringVar) and (StringH <> nil) then
  5847.                 StringH^^ := GetString
  5848.             else
  5849.                 value := GetBooleanExpression;
  5850.         end;
  5851.     end;
  5852.  
  5853.  
  5854.     procedure DoStatement;
  5855.     begin
  5856.         case token of
  5857.             BeginT: 
  5858.                 DoCompoundStatement;
  5859.             CommandT: 
  5860.                 ExecuteCommand;
  5861.             ForT: 
  5862.                 DoFor;
  5863.             IfT: 
  5864.                 DoIf;
  5865.             WhileT: 
  5866.                 DoWhile;
  5867.             RepeatT: 
  5868.                 DoRepeat;
  5869.             Identifier: 
  5870.                 MacroError('Undefined identifier');
  5871.             Variable: 
  5872.                 DoAssignment;
  5873.             StringVariable: 
  5874.                 DoStringAssignment;
  5875.             ArrayT: 
  5876.                 DoArrayAssignment;
  5877.             ProcedureT: 
  5878.                 DoProcedure;
  5879.             ElseT: 
  5880.                 MacroError('Statement expected');
  5881.             FunctionT, StringFunctionT: 
  5882.                 MacroError('Variable expected');
  5883.             UserFunctionT:
  5884.                 DoFunctionAssignment;
  5885.             SemiColon: 
  5886.                 PutTokenBack; {Null statement}
  5887.             otherwise
  5888.                 CannotBeginWithThis
  5889.         end;
  5890.     end;
  5891.  
  5892.  
  5893.     procedure SkipStatement;
  5894.     begin
  5895.         case token of
  5896.             BeginT: 
  5897.                 SkipCompoundStatement;
  5898.             ForT: 
  5899.                 SkipFor;
  5900.             IfT: 
  5901.                 SkipIf;
  5902.             WhileT: 
  5903.                 SkipWhile;
  5904.             RepeatT: 
  5905.                 SkipRepeat;
  5906.             CommandT, Variable, StringVariable, ArrayT, ProcedureT, UserFunctionT: 
  5907.                 SkipPartialStatement;
  5908.             DoneT: 
  5909.                 ; {Aborting the macro}
  5910.             SemiColon, EndT, ElseT, UntilT: 
  5911.                 PutTokenBack; {These tokens can follow a statement}
  5912.             otherwise
  5913.                 CannotBeginWithThis
  5914.         end;
  5915.     end;
  5916.  
  5917.  
  5918.  
  5919.     procedure RunMacro (nMacro: integer);
  5920.         var
  5921.             count: integer;
  5922.             str: str255;
  5923.             SaveInfo: InfoPtr;
  5924.     begin
  5925.         DefaultFileName := '';
  5926.         str := '';
  5927.         nSaves := 0;
  5928.         DefaultRefNum := 0;
  5929.         count := 0;
  5930.         pcStart := MacroStart[nMacro];
  5931.         pc := pcStart;
  5932.         SavePC := pcStart;
  5933.         LineStartPC := pcStart;
  5934.         token := NullT;
  5935.         macro := true;
  5936.         DoOption := false;
  5937.         SaveInfo := info;
  5938.         TopOfStack := nGlobals;
  5939.         MacroOrProcName := BlankSymbol;
  5940.         StringsAllocated := false;
  5941.         InPhotoMode := false;
  5942.         RoutinesCalled := [];
  5943.         MacroTicks := TickCount + 15;
  5944.         LoopCounter := 0;
  5945.         GetToken;
  5946.         DoDeclarations;
  5947.         DoCompoundStatement;
  5948.         if (info <> SaveInfo) and (info <> NoInfo) then
  5949.             SelectWindow(info^.wptr);
  5950.         with info^, RoiRect do begin
  5951.                 if ((right - left) <= 0) or ((bottom - top) <= 0) then
  5952.                     KillRoi;
  5953.             end;
  5954.         if info^.RoiShowing then
  5955.             if not (OpPending and (CurrentOp = PasteOp)) then begin
  5956.               KIllRoi;
  5957.               RestoreRoi;
  5958.             end;
  5959.         macro := false;
  5960.         if StringsAllocated then
  5961.             DeallocateStrings(nGlobals + 1, TopOfStack);
  5962.         if InPhotoMode then
  5963.             RestoreScreen;
  5964.     end;
  5965.  
  5966.  
  5967.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  5968.         const
  5969.             FunctionKey = 16;
  5970.         var
  5971.             i: integer;
  5972.     begin
  5973.         if (ord(ch) = 0) then
  5974.             exit(RunKeyMacro);
  5975.         if (ch >= 'A') and (ch <= 'Z') then
  5976.             ch := chr(ord(ch) + 32); {Convert to lower case}
  5977.         if ord(ch) = FunctionKey then
  5978.             case KeyCode of
  5979.                 122: 
  5980.                     ch := 'A';
  5981.                 120: 
  5982.                     ch := 'B';
  5983.                 99: 
  5984.                     ch := 'C';
  5985.                 118: 
  5986.                     ch := 'D';
  5987.                 96: 
  5988.                     ch := 'E';
  5989.                 97: 
  5990.                     ch := 'F';
  5991.                 98: 
  5992.                     ch := 'G';
  5993.                 100: 
  5994.                     ch := 'H';
  5995.                 101: 
  5996.                     ch := 'I';
  5997.                 109: 
  5998.                     ch := 'J';
  5999.                 103: 
  6000.                     ch := 'K';
  6001.                 111: 
  6002.                     ch := 'L';
  6003.                 105: 
  6004.                     ch := 'M';
  6005.                 107: 
  6006.                     ch := 'N';
  6007.                 113: 
  6008.                     ch := 'O';
  6009.                 otherwise
  6010.             end;
  6011.         for i := 1 to nMacros do
  6012.             if ch = MacroKey[i] then begin
  6013.                     RunMacro(i);
  6014.                     leave;
  6015.                 end;
  6016.     end;
  6017.  
  6018.  
  6019.  
  6020. end.